From 494f296a3baab08522617b24b1f126d8f9a17502 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Wed, 20 Jan 2016 16:26:51 +0100 Subject: Imported Upstream version 1.1.90 --- src/Makefile.am | 346 +- src/Makefile.in | 1099 +-- src/NetworkManagerUtils.c | 880 ++- src/NetworkManagerUtils.h | 251 +- src/devices/Makefile.am | 1 + src/devices/Makefile.in | 772 ++ src/devices/adsl/Makefile.am | 25 +- src/devices/adsl/Makefile.in | 62 +- src/devices/adsl/nm-adsl-enum-types.c | 12 - src/devices/adsl/nm-adsl-enum-types.h | 17 - src/devices/adsl/nm-atm-manager.c | 8 +- src/devices/adsl/nm-atm-manager.h | 3 +- src/devices/adsl/nm-device-adsl-glue.h | 73 - src/devices/adsl/nm-device-adsl.c | 32 +- src/devices/adsl/nm-device-adsl.h | 3 +- src/devices/bluetooth/Makefile.am | 18 +- src/devices/bluetooth/Makefile.in | 39 +- src/devices/bluetooth/nm-bluez-common.h | 2 +- src/devices/bluetooth/nm-bluez-device.c | 48 +- src/devices/bluetooth/nm-bluez-device.h | 6 +- src/devices/bluetooth/nm-bluez-manager.c | 28 +- src/devices/bluetooth/nm-bluez-manager.h | 3 +- src/devices/bluetooth/nm-bluez4-adapter.c | 95 +- src/devices/bluetooth/nm-bluez4-adapter.h | 3 +- src/devices/bluetooth/nm-bluez4-manager.c | 173 +- src/devices/bluetooth/nm-bluez4-manager.h | 7 +- src/devices/bluetooth/nm-bluez5-dun.c | 7 +- src/devices/bluetooth/nm-bluez5-dun.h | 3 +- src/devices/bluetooth/nm-bluez5-manager.c | 130 +- src/devices/bluetooth/nm-bluez5-manager.h | 7 +- src/devices/bluetooth/nm-bt-enum-types.c | 2 + src/devices/bluetooth/nm-bt-error.c | 2 +- src/devices/bluetooth/nm-device-bt-glue.h | 73 - src/devices/bluetooth/nm-device-bt.c | 107 +- src/devices/bluetooth/nm-device-bt.h | 2 +- src/devices/nm-device-bond.c | 164 +- src/devices/nm-device-bond.h | 4 - src/devices/nm-device-bridge.c | 195 +- src/devices/nm-device-bridge.h | 5 +- src/devices/nm-device-ethernet-utils.c | 3 +- src/devices/nm-device-ethernet-utils.h | 2 +- src/devices/nm-device-ethernet.c | 256 +- src/devices/nm-device-ethernet.h | 3 +- src/devices/nm-device-factory.c | 150 +- src/devices/nm-device-factory.h | 100 +- src/devices/nm-device-generic.c | 57 +- src/devices/nm-device-generic.h | 4 +- src/devices/nm-device-gre.c | 283 - src/devices/nm-device-gre.h | 55 - src/devices/nm-device-infiniband.c | 165 +- src/devices/nm-device-infiniband.h | 2 - src/devices/nm-device-ip-tunnel.c | 1052 +++ src/devices/nm-device-ip-tunnel.h | 60 + src/devices/nm-device-logging.h | 2 +- src/devices/nm-device-macvlan.c | 653 +- src/devices/nm-device-macvlan.h | 9 +- src/devices/nm-device-private.h | 13 +- src/devices/nm-device-tun.c | 356 +- src/devices/nm-device-tun.h | 6 +- src/devices/nm-device-veth.c | 43 +- src/devices/nm-device-veth.h | 2 - src/devices/nm-device-vlan.c | 538 +- src/devices/nm-device-vlan.h | 5 - src/devices/nm-device-vxlan.c | 602 +- src/devices/nm-device-vxlan.h | 6 +- src/devices/nm-device.c | 4145 +++++++---- src/devices/nm-device.h | 205 +- src/devices/nm-lldp-listener.c | 648 ++ src/devices/nm-lldp-listener.h | 57 + src/devices/team/Makefile.am | 30 +- src/devices/team/Makefile.in | 73 +- src/devices/team/nm-device-team-glue.h | 73 - src/devices/team/nm-device-team.c | 156 +- src/devices/team/nm-device-team.h | 18 +- src/devices/team/nm-team-enum-types.c | 12 - src/devices/team/nm-team-enum-types.h | 17 - src/devices/team/nm-team-factory.c | 26 +- src/devices/team/nm-team-factory.h | 2 +- src/devices/tests/Makefile.am | 42 + src/devices/tests/Makefile.in | 1193 ++++ src/devices/tests/test-lldp.c | 221 + src/devices/wifi/Makefile.am | 37 +- src/devices/wifi/Makefile.in | 80 +- src/devices/wifi/nm-device-olpc-mesh-glue.h | 73 - src/devices/wifi/nm-device-olpc-mesh.c | 90 +- src/devices/wifi/nm-device-olpc-mesh.h | 4 +- src/devices/wifi/nm-device-wifi-glue.h | 167 - src/devices/wifi/nm-device-wifi.c | 1379 ++-- src/devices/wifi/nm-device-wifi.h | 4 +- src/devices/wifi/nm-wifi-ap-utils.c | 3 +- src/devices/wifi/nm-wifi-ap.c | 1428 ++-- src/devices/wifi/nm-wifi-ap.h | 112 +- src/devices/wifi/nm-wifi-enum-types.c | 14 - src/devices/wifi/nm-wifi-enum-types.h | 17 - src/devices/wifi/nm-wifi-factory.c | 33 +- src/devices/wifi/tests/Makefile.am | 10 +- src/devices/wifi/tests/Makefile.in | 28 +- src/devices/wifi/tests/test-wifi-ap-utils.c | 13 +- src/devices/wimax/Makefile.am | 60 - src/devices/wimax/Makefile.in | 866 --- src/devices/wimax/exports.ver | 6 - src/devices/wimax/iwmxsdk.c | 1515 ---- src/devices/wimax/iwmxsdk.h | 112 - src/devices/wimax/nm-device-wimax.c | 1416 ---- src/devices/wimax/nm-device-wimax.h | 64 - src/devices/wimax/nm-wimax-factory.c | 91 - src/devices/wimax/nm-wimax-nsp.c | 241 - src/devices/wimax/nm-wimax-nsp.h | 63 - src/devices/wimax/nm-wimax-types.h | 31 - src/devices/wimax/nm-wimax-util.c | 83 - src/devices/wimax/nm-wimax-util.h | 43 - src/devices/wwan/Makefile.am | 24 +- src/devices/wwan/Makefile.in | 55 +- src/devices/wwan/nm-device-modem-glue.h | 73 - src/devices/wwan/nm-device-modem.c | 33 +- src/devices/wwan/nm-device-modem.h | 3 - src/devices/wwan/nm-modem-broadband.c | 368 +- src/devices/wwan/nm-modem-broadband.h | 1 - src/devices/wwan/nm-modem-enum-types.c | 2 + src/devices/wwan/nm-modem-manager.c | 15 +- src/devices/wwan/nm-modem-manager.h | 1 - src/devices/wwan/nm-modem.c | 171 +- src/devices/wwan/nm-modem.h | 50 +- src/devices/wwan/nm-wwan-factory.c | 17 +- src/devices/wwan/nm-wwan-factory.h | 2 +- src/dhcp-manager/Makefile.am | 16 +- src/dhcp-manager/Makefile.in | 106 +- src/dhcp-manager/nm-dhcp-client.c | 76 +- src/dhcp-manager/nm-dhcp-client.h | 13 +- src/dhcp-manager/nm-dhcp-dhclient-utils.c | 29 +- src/dhcp-manager/nm-dhcp-dhclient-utils.h | 7 +- src/dhcp-manager/nm-dhcp-dhclient.c | 28 +- src/dhcp-manager/nm-dhcp-dhclient.h | 4 +- src/dhcp-manager/nm-dhcp-dhcpcd.c | 31 +- src/dhcp-manager/nm-dhcp-dhcpcd.h | 3 - src/dhcp-manager/nm-dhcp-helper.c | 84 +- src/dhcp-manager/nm-dhcp-helper.conf | 13 - src/dhcp-manager/nm-dhcp-listener.c | 178 +- src/dhcp-manager/nm-dhcp-listener.h | 3 +- src/dhcp-manager/nm-dhcp-manager.c | 33 +- src/dhcp-manager/nm-dhcp-manager.h | 6 +- src/dhcp-manager/nm-dhcp-systemd.c | 96 +- src/dhcp-manager/nm-dhcp-systemd.h | 3 - src/dhcp-manager/nm-dhcp-utils.c | 27 +- src/dhcp-manager/nm-dhcp-utils.h | 10 +- src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c | 236 - src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h | 132 - .../src/libsystemd-network/dhcp-internal.h | 76 - .../src/libsystemd-network/dhcp-lease-internal.h | 89 - .../src/libsystemd-network/dhcp-network.c | 241 - .../src/libsystemd-network/dhcp-option.c | 257 - .../src/libsystemd-network/dhcp-packet.c | 204 - .../src/libsystemd-network/dhcp-protocol.h | 142 - .../src/libsystemd-network/dhcp6-internal.h | 81 - .../src/libsystemd-network/dhcp6-lease-internal.h | 64 - .../src/libsystemd-network/dhcp6-network.c | 198 - .../src/libsystemd-network/dhcp6-option.c | 323 - .../src/libsystemd-network/dhcp6-protocol.h | 141 - .../src/libsystemd-network/network-internal.c | 484 -- .../src/libsystemd-network/network-internal.h | 78 - .../src/libsystemd-network/sd-dhcp-client.c | 1726 ----- .../src/libsystemd-network/sd-dhcp-lease.c | 917 --- .../src/libsystemd-network/sd-dhcp6-client.c | 1250 ---- .../src/libsystemd-network/sd-dhcp6-lease.c | 223 - src/dhcp-manager/systemd-dhcp/src/shared/async.h | 27 - src/dhcp-manager/systemd-dhcp/src/shared/fileio.c | 817 --- src/dhcp-manager/systemd-dhcp/src/shared/fileio.h | 45 - .../systemd-dhcp/src/shared/in-addr-util.c | 294 - .../systemd-dhcp/src/shared/in-addr-util.h | 49 - src/dhcp-manager/systemd-dhcp/src/shared/list.h | 138 - src/dhcp-manager/systemd-dhcp/src/shared/macro.h | 422 -- src/dhcp-manager/systemd-dhcp/src/shared/refcnt.h | 34 - .../systemd-dhcp/src/shared/siphash24.c | 137 - .../systemd-dhcp/src/shared/siphash24.h | 6 - .../systemd-dhcp/src/shared/socket-util.h | 118 - .../systemd-dhcp/src/shared/sparse-endian.h | 88 - src/dhcp-manager/systemd-dhcp/src/shared/strv.c | 616 -- src/dhcp-manager/systemd-dhcp/src/shared/strv.h | 137 - .../systemd-dhcp/src/shared/time-util.c | 1003 --- .../systemd-dhcp/src/shared/time-util.h | 111 - .../systemd-dhcp/src/shared/unaligned.h | 66 - src/dhcp-manager/systemd-dhcp/src/shared/utf8.c | 314 - src/dhcp-manager/systemd-dhcp/src/shared/utf8.h | 42 - src/dhcp-manager/systemd-dhcp/src/shared/util.c | 7350 -------------------- src/dhcp-manager/systemd-dhcp/src/shared/util.h | 1038 --- .../systemd-dhcp/src/systemd/_sd-common.h | 78 - .../systemd-dhcp/src/systemd/sd-dhcp-client.h | 75 - .../systemd-dhcp/src/systemd/sd-dhcp-lease.h | 55 - .../systemd-dhcp/src/systemd/sd-dhcp6-client.h | 66 - .../systemd-dhcp/src/systemd/sd-dhcp6-lease.h | 42 - .../systemd-dhcp/src/systemd/sd-event.h | 135 - .../systemd-dhcp/src/systemd/sd-id128.h | 113 - src/dhcp-manager/tests/Makefile.am | 6 +- src/dhcp-manager/tests/Makefile.in | 24 +- src/dhcp-manager/tests/test-dhcp-dhclient.c | 76 +- src/dhcp-manager/tests/test-dhcp-utils.c | 43 +- src/dns-manager/nm-dns-dnsmasq.c | 74 +- src/dns-manager/nm-dns-dnsmasq.h | 3 - src/dns-manager/nm-dns-manager.c | 684 +- src/dns-manager/nm-dns-manager.h | 38 +- src/dns-manager/nm-dns-plugin.c | 10 +- src/dns-manager/nm-dns-plugin.h | 10 +- src/dns-manager/nm-dns-unbound.c | 3 +- src/dns-manager/nm-dns-unbound.h | 2 - src/dnsmasq-manager/nm-dnsmasq-manager.c | 26 +- src/dnsmasq-manager/nm-dnsmasq-manager.h | 6 +- src/dnsmasq-manager/nm-dnsmasq-utils.h | 2 +- src/dnsmasq-manager/tests/Makefile.am | 6 +- src/dnsmasq-manager/tests/Makefile.in | 24 +- src/dnsmasq-manager/tests/test-dnsmasq-utils.c | 47 +- src/main-utils.c | 7 +- src/main-utils.h | 2 +- src/main.c | 110 +- src/nm-access-point-glue.h | 73 - src/nm-activation-request.c | 214 +- src/nm-activation-request.h | 42 +- src/nm-active-connection-glue.h | 73 - src/nm-active-connection.c | 439 +- src/nm-active-connection.h | 30 +- src/nm-agent-manager-glue.h | 170 - src/nm-audit-manager.c | 389 ++ src/nm-audit-manager.h | 114 + src/nm-auth-manager.c | 66 +- src/nm-auth-manager.h | 2 +- src/nm-auth-subject.c | 40 +- src/nm-auth-subject.h | 12 +- src/nm-auth-utils.c | 157 +- src/nm-auth-utils.h | 15 +- src/nm-bus-manager.c | 949 +++ src/nm-bus-manager.h | 111 + src/nm-config-data.c | 797 ++- src/nm-config-data.h | 51 +- src/nm-config.c | 1081 ++- src/nm-config.h | 48 +- src/nm-connection-provider.c | 35 +- src/nm-connection-provider.h | 15 +- src/nm-connectivity.c | 9 +- src/nm-connectivity.h | 5 +- src/nm-dbus-manager.c | 998 --- src/nm-dbus-manager.h | 133 - src/nm-dcb.c | 3 +- src/nm-dcb.h | 2 +- src/nm-default-route-manager.c | 25 +- src/nm-default-route-manager.h | 3 +- src/nm-device-bond-glue.h | 73 - src/nm-device-bridge-glue.h | 73 - src/nm-device-ethernet-glue.h | 73 - src/nm-device-generic-glue.h | 73 - src/nm-device-glue.h | 79 - src/nm-device-gre-glue.h | 73 - src/nm-device-infiniband-glue.h | 73 - src/nm-device-macvlan-glue.h | 73 - src/nm-device-tun-glue.h | 73 - src/nm-device-veth-glue.h | 73 - src/nm-device-vlan-glue.h | 73 - src/nm-device-vxlan-glue.h | 73 - src/nm-dhcp4-config-glue.h | 73 - src/nm-dhcp4-config.c | 116 +- src/nm-dhcp4-config.h | 20 +- src/nm-dhcp6-config-glue.h | 73 - src/nm-dhcp6-config.c | 116 +- src/nm-dhcp6-config.h | 20 +- src/nm-dispatcher.c | 571 +- src/nm-dispatcher.h | 15 +- src/nm-enum-types.c | 212 +- src/nm-enum-types.h | 26 +- src/nm-exported-object.c | 883 +++ src/nm-exported-object.h | 85 + src/nm-firewall-manager.c | 578 +- src/nm-firewall-manager.h | 29 +- src/nm-iface-helper.c | 71 +- src/nm-ip4-config-glue.h | 73 - src/nm-ip4-config.c | 598 +- src/nm-ip4-config.h | 34 +- src/nm-ip6-config-glue.h | 73 - src/nm-ip6-config.c | 557 +- src/nm-ip6-config.h | 31 +- src/nm-logging.c | 566 +- src/nm-logging.h | 52 +- src/nm-manager-glue.h | 416 -- src/nm-manager.c | 2439 ++++--- src/nm-manager.h | 28 +- src/nm-multi-index.c | 157 +- src/nm-multi-index.h | 7 +- src/nm-policy.c | 213 +- src/nm-policy.h | 2 +- src/nm-ppp-manager-glue.h | 175 - src/nm-properties-changed-signal.c | 248 - src/nm-properties-changed-signal.h | 31 - src/nm-rfkill-manager.c | 4 +- src/nm-rfkill-manager.h | 10 +- src/nm-route-manager.c | 35 +- src/nm-route-manager.h | 3 +- src/nm-session-monitor-ck.c | 503 -- src/nm-session-monitor-null.c | 169 - src/nm-session-monitor-systemd.c | 268 - src/nm-session-monitor.c | 450 ++ src/nm-session-monitor.h | 32 +- src/nm-session-utils.c | 70 - src/nm-session-utils.h | 30 - src/nm-settings-connection-glue.h | 172 - src/nm-settings-glue.h | 219 - src/nm-sleep-monitor-systemd.c | 49 +- src/nm-sleep-monitor-upower.c | 124 +- src/nm-sleep-monitor.h | 3 +- src/nm-types.h | 27 +- src/nm-vpn-connection-glue.h | 73 - src/org.freedesktop.NetworkManager.conf | 16 +- src/platform/Makefile.in | 18 +- src/platform/nm-fake-platform.c | 379 +- src/platform/nm-linux-platform.c | 6695 ++++++++++-------- src/platform/nm-linux-platform.h | 2 + src/platform/nm-platform-utils.c | 3 +- src/platform/nm-platform.c | 1731 ++++- src/platform/nm-platform.h | 467 +- src/platform/nmp-object.c | 663 +- src/platform/nmp-object.h | 114 +- src/platform/tests/Makefile.am | 6 +- src/platform/tests/Makefile.in | 24 +- src/platform/tests/monitor.c | 44 +- src/platform/tests/test-address.c | 278 +- src/platform/tests/test-cleanup.c | 6 +- src/platform/tests/test-common.c | 1222 +++- src/platform/tests/test-common.h | 131 +- src/platform/tests/test-general.c | 3 +- src/platform/tests/test-link.c | 1351 +++- src/platform/tests/test-nmp-object.c | 6 +- src/platform/tests/test-route.c | 38 +- src/platform/wifi/wifi-utils-nl80211.c | 287 +- src/platform/wifi/wifi-utils-private.h | 8 +- src/platform/wifi/wifi-utils-wext.c | 60 +- src/platform/wifi/wifi-utils.c | 17 +- src/platform/wifi/wifi-utils.h | 7 +- src/ppp-manager/Makefile.am | 7 +- src/ppp-manager/Makefile.in | 25 +- src/ppp-manager/nm-ppp-manager.c | 420 +- src/ppp-manager/nm-ppp-manager.h | 11 +- src/ppp-manager/nm-pppd-plugin.c | 6 +- src/ppp-manager/nm-pppd-plugin.h | 2 - src/rdisc/Makefile.in | 18 +- src/rdisc/nm-fake-rdisc.c | 126 +- src/rdisc/nm-fake-rdisc.h | 10 +- src/rdisc/nm-lndp-rdisc.c | 67 +- src/rdisc/nm-lndp-rdisc.h | 6 +- src/rdisc/nm-rdisc-private.h | 39 +- src/rdisc/nm-rdisc.c | 196 +- src/rdisc/nm-rdisc.h | 9 +- src/rdisc/tests/Makefile.am | 7 +- src/rdisc/tests/Makefile.in | 25 +- src/rdisc/tests/test-rdisc-fake.c | 34 +- src/rdisc/tests/test-rdisc-linux.c | 15 +- src/settings/nm-agent-manager.c | 1388 ++-- src/settings/nm-agent-manager.h | 57 +- src/settings/nm-inotify-helper.c | 4 +- src/settings/nm-inotify-helper.h | 4 +- src/settings/nm-secret-agent.c | 609 +- src/settings/nm-secret-agent.h | 58 +- src/settings/nm-settings-connection.c | 1078 ++- src/settings/nm-settings-connection.h | 44 +- src/settings/nm-settings-plugin.c | 179 + src/settings/nm-settings-plugin.h | 161 + src/settings/nm-settings.c | 1017 ++- src/settings/nm-settings.h | 16 +- src/settings/nm-system-config-interface.c | 216 - src/settings/nm-system-config-interface.h | 166 - src/settings/plugins/Makefile.am | 6 +- src/settings/plugins/Makefile.in | 31 +- src/settings/plugins/README | 33 + src/settings/plugins/example/Makefile.am | 33 - src/settings/plugins/example/Makefile.in | 779 --- src/settings/plugins/example/README | 35 - src/settings/plugins/example/common.h | 45 - .../plugins/example/nm-example-connection.c | 189 - .../plugins/example/nm-example-connection.h | 55 - src/settings/plugins/example/plugin.c | 858 --- src/settings/plugins/example/plugin.h | 55 - src/settings/plugins/example/reader.c | 47 - src/settings/plugins/example/writer.c | 56 - src/settings/plugins/ibft/Makefile.am | 7 +- src/settings/plugins/ibft/Makefile.in | 25 +- src/settings/plugins/ibft/plugin.c | 90 +- src/settings/plugins/ibft/plugin.h | 24 +- src/settings/plugins/ibft/reader.c | 5 +- src/settings/plugins/ibft/reader.h | 3 +- src/settings/plugins/ibft/tests/Makefile.am | 7 +- src/settings/plugins/ibft/tests/Makefile.in | 25 +- src/settings/plugins/ibft/tests/test-ibft.c | 2 +- src/settings/plugins/ifcfg-rh/Makefile.am | 35 +- src/settings/plugins/ifcfg-rh/Makefile.in | 71 +- src/settings/plugins/ifcfg-rh/common.h | 2 +- .../plugins/ifcfg-rh/nm-ifcfg-connection.c | 32 +- src/settings/plugins/ifcfg-rh/nm-ifcfg-rh.conf | 1 - src/settings/plugins/ifcfg-rh/nm-ifcfg-rh.xml | 1 - src/settings/plugins/ifcfg-rh/plugin.c | 711 +- src/settings/plugins/ifcfg-rh/plugin.h | 24 +- src/settings/plugins/ifcfg-rh/reader.c | 238 +- src/settings/plugins/ifcfg-rh/reader.h | 2 +- src/settings/plugins/ifcfg-rh/shvar.c | 80 +- src/settings/plugins/ifcfg-rh/shvar.h | 7 +- src/settings/plugins/ifcfg-rh/tests/Makefile.am | 7 +- src/settings/plugins/ifcfg-rh/tests/Makefile.in | 25 +- .../ifcfg-rh/tests/network-scripts/Makefile.am | 7 + .../ifcfg-rh/tests/network-scripts/Makefile.in | 25 +- .../tests/network-scripts/ifcfg-test-bridge-main | 2 +- .../tests/network-scripts/ifcfg-test-dns-options | 15 + .../tests/network-scripts/ifcfg-test-vlan-flags-1 | 14 + .../tests/network-scripts/ifcfg-test-vlan-flags-2 | 11 + .../ifcfg-test-wifi-mac-random-always | 7 + .../ifcfg-test-wifi-mac-random-default | 6 + .../ifcfg-test-wifi-mac-random-missing | 6 + .../ifcfg-test-wifi-mac-random-never | 6 + .../tests/network-scripts/ifcfg-test-wired-static | 1 + .../ifcfg-test-wired-static-bootproto | 1 + .../plugins/ifcfg-rh/tests/test-ifcfg-rh.c | 472 +- src/settings/plugins/ifcfg-rh/utils.c | 3 +- src/settings/plugins/ifcfg-rh/utils.h | 3 +- src/settings/plugins/ifcfg-rh/writer.c | 166 +- src/settings/plugins/ifcfg-rh/writer.h | 4 +- src/settings/plugins/ifcfg-suse/Makefile.am | 20 - src/settings/plugins/ifcfg-suse/Makefile.in | 819 --- src/settings/plugins/ifcfg-suse/plugin.c | 312 - src/settings/plugins/ifcfg-suse/plugin.h | 50 - src/settings/plugins/ifnet/Makefile.am | 6 +- src/settings/plugins/ifnet/Makefile.in | 24 +- src/settings/plugins/ifnet/connection_parser.c | 5 +- src/settings/plugins/ifnet/net_parser.c | 4 +- src/settings/plugins/ifnet/net_parser.h | 2 +- src/settings/plugins/ifnet/net_utils.c | 50 +- src/settings/plugins/ifnet/net_utils.h | 6 +- src/settings/plugins/ifnet/nm-ifnet-connection.c | 11 +- src/settings/plugins/ifnet/plugin.c | 201 +- src/settings/plugins/ifnet/plugin.h | 24 +- src/settings/plugins/ifnet/tests/Makefile.am | 23 +- src/settings/plugins/ifnet/tests/Makefile.in | 446 +- src/settings/plugins/ifnet/tests/hostname | 2 - src/settings/plugins/ifnet/tests/test-ifnet.c | 398 ++ src/settings/plugins/ifnet/tests/test_all.c | 488 -- src/settings/plugins/ifnet/wpa_parser.c | 4 +- src/settings/plugins/ifnet/wpa_parser.h | 2 +- src/settings/plugins/ifupdown/Makefile.am | 6 +- src/settings/plugins/ifupdown/Makefile.in | 24 +- src/settings/plugins/ifupdown/interface_parser.c | 2 +- src/settings/plugins/ifupdown/interface_parser.h | 2 +- .../plugins/ifupdown/nm-ifupdown-connection.c | 4 +- .../plugins/ifupdown/nm-ifupdown-connection.h | 1 + src/settings/plugins/ifupdown/parser.c | 4 +- src/settings/plugins/ifupdown/plugin.c | 252 +- src/settings/plugins/ifupdown/plugin.h | 24 +- src/settings/plugins/ifupdown/tests/Makefile.am | 6 +- src/settings/plugins/ifupdown/tests/Makefile.in | 24 +- .../plugins/ifupdown/tests/test-ifupdown.c | 13 +- src/settings/plugins/keyfile/Makefile.am | 10 +- src/settings/plugins/keyfile/Makefile.in | 28 +- src/settings/plugins/keyfile/common.h | 32 - .../plugins/keyfile/nm-keyfile-connection.c | 30 +- src/settings/plugins/keyfile/plugin.c | 395 +- src/settings/plugins/keyfile/plugin.h | 20 +- src/settings/plugins/keyfile/reader.c | 2 +- src/settings/plugins/keyfile/reader.h | 3 +- src/settings/plugins/keyfile/tests/Makefile.am | 8 +- src/settings/plugins/keyfile/tests/Makefile.in | 28 +- .../keyfile/tests/keyfiles/ATT_Data_Connect_Plain | 3 + .../plugins/keyfile/tests/keyfiles/Makefile.in | 18 +- .../keyfile/tests/keyfiles/Test_Bridge_Main | 1 + src/settings/plugins/keyfile/tests/test-keyfile.c | 174 +- src/settings/plugins/keyfile/utils.c | 25 +- src/settings/plugins/keyfile/utils.h | 7 +- src/settings/plugins/keyfile/writer.c | 65 +- src/settings/plugins/keyfile/writer.h | 4 +- src/supplicant-manager/nm-supplicant-config.c | 514 +- src/supplicant-manager/nm-supplicant-config.h | 19 +- src/supplicant-manager/nm-supplicant-interface.c | 414 +- src/supplicant-manager/nm-supplicant-interface.h | 30 +- src/supplicant-manager/nm-supplicant-manager.c | 36 +- src/supplicant-manager/nm-supplicant-manager.h | 2 +- .../nm-supplicant-settings-verify.c | 2 +- src/supplicant-manager/nm-supplicant-types.h | 20 + src/supplicant-manager/tests/Makefile.am | 9 +- src/supplicant-manager/tests/Makefile.in | 27 +- src/supplicant-manager/tests/certs/Makefile.in | 18 +- .../tests/test-supplicant-config.c | 52 +- src/systemd/nm-sd-adapt.c | 237 + src/systemd/nm-sd-adapt.h | 152 + src/systemd/src/basic/alloc-util.c | 87 + src/systemd/src/basic/alloc-util.h | 111 + src/systemd/src/basic/async.h | 29 + src/systemd/src/basic/escape.c | 493 ++ src/systemd/src/basic/escape.h | 55 + src/systemd/src/basic/fd-util.c | 366 + src/systemd/src/basic/fd-util.h | 77 + src/systemd/src/basic/fileio.c | 1261 ++++ src/systemd/src/basic/fileio.h | 86 + src/systemd/src/basic/fs-util.c | 526 ++ src/systemd/src/basic/fs-util.h | 79 + src/systemd/src/basic/hashmap.c | 1871 +++++ src/systemd/src/basic/hashmap.h | 417 ++ src/systemd/src/basic/hexdecoct.c | 702 ++ src/systemd/src/basic/hexdecoct.h | 57 + src/systemd/src/basic/hostname-util.c | 230 + src/systemd/src/basic/hostname-util.h | 44 + src/systemd/src/basic/in-addr-util.c | 360 + src/systemd/src/basic/in-addr-util.h | 58 + src/systemd/src/basic/io-util.c | 268 + src/systemd/src/basic/io-util.h | 81 + src/systemd/src/basic/list.h | 186 + src/systemd/src/basic/log.h | 246 + src/systemd/src/basic/macro.h | 379 + src/systemd/src/basic/mempool.c | 108 + src/systemd/src/basic/mempool.h | 51 + src/systemd/src/basic/parse-util.c | 542 ++ src/systemd/src/basic/parse-util.h | 99 + src/systemd/src/basic/path-util.c | 813 +++ src/systemd/src/basic/path-util.h | 115 + src/systemd/src/basic/prioq.c | 324 + src/systemd/src/basic/prioq.h | 47 + src/systemd/src/basic/random-util.c | 140 + src/systemd/src/basic/random-util.h | 41 + src/systemd/src/basic/refcnt.h | 38 + src/systemd/src/basic/set.h | 137 + src/systemd/src/basic/siphash24.c | 193 + src/systemd/src/basic/siphash24.h | 23 + src/systemd/src/basic/socket-util.h | 141 + src/systemd/src/basic/sparse-endian.h | 90 + src/systemd/src/basic/string-table.c | 38 + src/systemd/src/basic/string-table.h | 91 + src/systemd/src/basic/string-util.c | 813 +++ src/systemd/src/basic/string-util.h | 188 + src/systemd/src/basic/strv.c | 879 +++ src/systemd/src/basic/strv.h | 177 + src/systemd/src/basic/time-util.c | 1154 +++ src/systemd/src/basic/time-util.h | 131 + src/systemd/src/basic/umask-util.h | 50 + src/systemd/src/basic/unaligned.h | 115 + src/systemd/src/basic/utf8.c | 405 ++ src/systemd/src/basic/utf8.h | 61 + src/systemd/src/basic/util.c | 813 +++ src/systemd/src/basic/util.h | 186 + src/systemd/src/libsystemd-network/arp-util.c | 156 + src/systemd/src/libsystemd-network/arp-util.h | 36 + .../src/libsystemd-network/dhcp-identifier.c | 116 + .../src/libsystemd-network/dhcp-identifier.h | 67 + src/systemd/src/libsystemd-network/dhcp-internal.h | 72 + .../src/libsystemd-network/dhcp-lease-internal.h | 106 + src/systemd/src/libsystemd-network/dhcp-network.c | 237 + src/systemd/src/libsystemd-network/dhcp-option.c | 272 + src/systemd/src/libsystemd-network/dhcp-packet.c | 193 + src/systemd/src/libsystemd-network/dhcp-protocol.h | 159 + .../src/libsystemd-network/dhcp6-internal.h | 84 + .../src/libsystemd-network/dhcp6-lease-internal.h | 78 + src/systemd/src/libsystemd-network/dhcp6-network.c | 93 + src/systemd/src/libsystemd-network/dhcp6-option.c | 416 ++ .../src/libsystemd-network/dhcp6-protocol.h | 152 + src/systemd/src/libsystemd-network/lldp-internal.c | 364 + src/systemd/src/libsystemd-network/lldp-internal.h | 95 + src/systemd/src/libsystemd-network/lldp-network.c | 87 + src/systemd/src/libsystemd-network/lldp-network.h | 29 + src/systemd/src/libsystemd-network/lldp-port.c | 120 + src/systemd/src/libsystemd-network/lldp-port.h | 73 + src/systemd/src/libsystemd-network/lldp-tlv.c | 642 ++ src/systemd/src/libsystemd-network/lldp-tlv.h | 98 + src/systemd/src/libsystemd-network/lldp.h | 130 + .../src/libsystemd-network/network-internal.c | 560 ++ .../src/libsystemd-network/network-internal.h | 85 + .../src/libsystemd-network/sd-dhcp-client.c | 1781 +++++ src/systemd/src/libsystemd-network/sd-dhcp-lease.c | 1145 +++ .../src/libsystemd-network/sd-dhcp6-client.c | 1309 ++++ .../src/libsystemd-network/sd-dhcp6-lease.c | 414 ++ src/systemd/src/libsystemd-network/sd-ipv4acd.c | 529 ++ src/systemd/src/libsystemd-network/sd-ipv4ll.c | 366 + src/systemd/src/libsystemd-network/sd-lldp.c | 760 ++ src/systemd/src/libsystemd/sd-id128/sd-id128.c | 233 + src/systemd/src/shared/dns-domain.c | 1249 ++++ src/systemd/src/shared/dns-domain.h | 107 + src/systemd/src/systemd/_sd-common.h | 87 + src/systemd/src/systemd/sd-dhcp-client.h | 86 + src/systemd/src/systemd/sd-dhcp-lease.h | 67 + src/systemd/src/systemd/sd-dhcp6-client.h | 81 + src/systemd/src/systemd/sd-dhcp6-lease.h | 56 + src/systemd/src/systemd/sd-event.h | 142 + src/systemd/src/systemd/sd-id128.h | 119 + src/systemd/src/systemd/sd-ipv4acd.h | 64 + src/systemd/src/systemd/sd-ipv4ll.h | 64 + src/systemd/src/systemd/sd-lldp.h | 91 + src/systemd/src/systemd/sd-ndisc.h | 88 + src/tests/Makefile.am | 33 +- src/tests/Makefile.in | 83 +- src/tests/config/Makefile.am | 12 +- src/tests/config/Makefile.in | 30 +- src/tests/config/NetworkManager.conf | 16 + src/tests/config/conf.d/20-config-enable-1.conf | 5 + src/tests/config/global-dns-invalid.conf | 9 + src/tests/config/nm-test-device.h | 2 +- src/tests/config/test-config.c | 498 +- src/tests/test-dcb.c | 12 +- src/tests/test-general-with-expect.c | 5 +- src/tests/test-general.c | 315 +- src/tests/test-ip4-config.c | 28 +- src/tests/test-ip6-config.c | 19 +- src/tests/test-resolvconf-capture.c | 114 +- src/tests/test-route-manager.c | 19 +- src/tests/test-utils.c | 63 + src/tests/test-wired-defname.c | 14 +- src/vpn-manager/nm-vpn-connection.c | 1915 ++--- src/vpn-manager/nm-vpn-connection.h | 41 +- src/vpn-manager/nm-vpn-manager.c | 285 +- src/vpn-manager/nm-vpn-manager.h | 7 +- src/vpn-manager/nm-vpn-service.c | 385 - src/vpn-manager/nm-vpn-service.h | 63 - 608 files changed, 72284 insertions(+), 55763 deletions(-) create mode 100644 src/devices/Makefile.am create mode 100644 src/devices/Makefile.in delete mode 100644 src/devices/adsl/nm-adsl-enum-types.c delete mode 100644 src/devices/adsl/nm-adsl-enum-types.h delete mode 100644 src/devices/adsl/nm-device-adsl-glue.h delete mode 100644 src/devices/bluetooth/nm-device-bt-glue.h delete mode 100644 src/devices/nm-device-gre.c delete mode 100644 src/devices/nm-device-gre.h create mode 100644 src/devices/nm-device-ip-tunnel.c create mode 100644 src/devices/nm-device-ip-tunnel.h create mode 100644 src/devices/nm-lldp-listener.c create mode 100644 src/devices/nm-lldp-listener.h delete mode 100644 src/devices/team/nm-device-team-glue.h delete mode 100644 src/devices/team/nm-team-enum-types.c delete mode 100644 src/devices/team/nm-team-enum-types.h create mode 100644 src/devices/tests/Makefile.am create mode 100644 src/devices/tests/Makefile.in create mode 100644 src/devices/tests/test-lldp.c delete mode 100644 src/devices/wifi/nm-device-olpc-mesh-glue.h delete mode 100644 src/devices/wifi/nm-device-wifi-glue.h delete mode 100644 src/devices/wifi/nm-wifi-enum-types.c delete mode 100644 src/devices/wifi/nm-wifi-enum-types.h delete mode 100644 src/devices/wimax/Makefile.am delete mode 100644 src/devices/wimax/Makefile.in delete mode 100644 src/devices/wimax/exports.ver delete mode 100644 src/devices/wimax/iwmxsdk.c delete mode 100644 src/devices/wimax/iwmxsdk.h delete mode 100644 src/devices/wimax/nm-device-wimax.c delete mode 100644 src/devices/wimax/nm-device-wimax.h delete mode 100644 src/devices/wimax/nm-wimax-factory.c delete mode 100644 src/devices/wimax/nm-wimax-nsp.c delete mode 100644 src/devices/wimax/nm-wimax-nsp.h delete mode 100644 src/devices/wimax/nm-wimax-types.h delete mode 100644 src/devices/wimax/nm-wimax-util.c delete mode 100644 src/devices/wimax/nm-wimax-util.h delete mode 100644 src/devices/wwan/nm-device-modem-glue.h delete mode 100644 src/dhcp-manager/nm-dhcp-helper.conf delete mode 100644 src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c delete mode 100644 src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-internal.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-option.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-protocol.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-internal.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-lease-internal.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-network.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-protocol.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/async.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/fileio.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/fileio.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/list.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/macro.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/refcnt.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/siphash24.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/siphash24.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/socket-util.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/sparse-endian.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/strv.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/strv.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/time-util.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/time-util.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/unaligned.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/utf8.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/utf8.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/util.c delete mode 100644 src/dhcp-manager/systemd-dhcp/src/shared/util.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/systemd/_sd-common.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-client.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-lease.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-lease.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/systemd/sd-event.h delete mode 100644 src/dhcp-manager/systemd-dhcp/src/systemd/sd-id128.h delete mode 100644 src/nm-access-point-glue.h delete mode 100644 src/nm-active-connection-glue.h delete mode 100644 src/nm-agent-manager-glue.h create mode 100644 src/nm-audit-manager.c create mode 100644 src/nm-audit-manager.h create mode 100644 src/nm-bus-manager.c create mode 100644 src/nm-bus-manager.h delete mode 100644 src/nm-dbus-manager.c delete mode 100644 src/nm-dbus-manager.h delete mode 100644 src/nm-device-bond-glue.h delete mode 100644 src/nm-device-bridge-glue.h delete mode 100644 src/nm-device-ethernet-glue.h delete mode 100644 src/nm-device-generic-glue.h delete mode 100644 src/nm-device-glue.h delete mode 100644 src/nm-device-gre-glue.h delete mode 100644 src/nm-device-infiniband-glue.h delete mode 100644 src/nm-device-macvlan-glue.h delete mode 100644 src/nm-device-tun-glue.h delete mode 100644 src/nm-device-veth-glue.h delete mode 100644 src/nm-device-vlan-glue.h delete mode 100644 src/nm-device-vxlan-glue.h delete mode 100644 src/nm-dhcp4-config-glue.h delete mode 100644 src/nm-dhcp6-config-glue.h create mode 100644 src/nm-exported-object.c create mode 100644 src/nm-exported-object.h delete mode 100644 src/nm-ip4-config-glue.h delete mode 100644 src/nm-ip6-config-glue.h delete mode 100644 src/nm-manager-glue.h delete mode 100644 src/nm-ppp-manager-glue.h delete mode 100644 src/nm-properties-changed-signal.c delete mode 100644 src/nm-properties-changed-signal.h delete mode 100644 src/nm-session-monitor-ck.c delete mode 100644 src/nm-session-monitor-null.c delete mode 100644 src/nm-session-monitor-systemd.c create mode 100644 src/nm-session-monitor.c delete mode 100644 src/nm-session-utils.c delete mode 100644 src/nm-session-utils.h delete mode 100644 src/nm-settings-connection-glue.h delete mode 100644 src/nm-settings-glue.h delete mode 100644 src/nm-vpn-connection-glue.h create mode 100644 src/settings/nm-settings-plugin.c create mode 100644 src/settings/nm-settings-plugin.h delete mode 100644 src/settings/nm-system-config-interface.c delete mode 100644 src/settings/nm-system-config-interface.h create mode 100644 src/settings/plugins/README delete mode 100644 src/settings/plugins/example/Makefile.am delete mode 100644 src/settings/plugins/example/Makefile.in delete mode 100644 src/settings/plugins/example/README delete mode 100644 src/settings/plugins/example/common.h delete mode 100644 src/settings/plugins/example/nm-example-connection.c delete mode 100644 src/settings/plugins/example/nm-example-connection.h delete mode 100644 src/settings/plugins/example/plugin.c delete mode 100644 src/settings/plugins/example/plugin.h delete mode 100644 src/settings/plugins/example/reader.c delete mode 100644 src/settings/plugins/example/writer.c create mode 100644 src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options create mode 100644 src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-flags-1 create mode 100644 src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-flags-2 create mode 100644 src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-always create mode 100644 src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-default create mode 100644 src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-missing create mode 100644 src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-never delete mode 100644 src/settings/plugins/ifcfg-suse/Makefile.am delete mode 100644 src/settings/plugins/ifcfg-suse/Makefile.in delete mode 100644 src/settings/plugins/ifcfg-suse/plugin.c delete mode 100644 src/settings/plugins/ifcfg-suse/plugin.h delete mode 100644 src/settings/plugins/ifnet/tests/hostname create mode 100644 src/settings/plugins/ifnet/tests/test-ifnet.c delete mode 100644 src/settings/plugins/ifnet/tests/test_all.c delete mode 100644 src/settings/plugins/keyfile/common.h create mode 100644 src/systemd/nm-sd-adapt.c create mode 100644 src/systemd/nm-sd-adapt.h create mode 100644 src/systemd/src/basic/alloc-util.c create mode 100644 src/systemd/src/basic/alloc-util.h create mode 100644 src/systemd/src/basic/async.h create mode 100644 src/systemd/src/basic/escape.c create mode 100644 src/systemd/src/basic/escape.h create mode 100644 src/systemd/src/basic/fd-util.c create mode 100644 src/systemd/src/basic/fd-util.h create mode 100644 src/systemd/src/basic/fileio.c create mode 100644 src/systemd/src/basic/fileio.h create mode 100644 src/systemd/src/basic/fs-util.c create mode 100644 src/systemd/src/basic/fs-util.h create mode 100644 src/systemd/src/basic/hashmap.c create mode 100644 src/systemd/src/basic/hashmap.h create mode 100644 src/systemd/src/basic/hexdecoct.c create mode 100644 src/systemd/src/basic/hexdecoct.h create mode 100644 src/systemd/src/basic/hostname-util.c create mode 100644 src/systemd/src/basic/hostname-util.h create mode 100644 src/systemd/src/basic/in-addr-util.c create mode 100644 src/systemd/src/basic/in-addr-util.h create mode 100644 src/systemd/src/basic/io-util.c create mode 100644 src/systemd/src/basic/io-util.h create mode 100644 src/systemd/src/basic/list.h create mode 100644 src/systemd/src/basic/log.h create mode 100644 src/systemd/src/basic/macro.h create mode 100644 src/systemd/src/basic/mempool.c create mode 100644 src/systemd/src/basic/mempool.h create mode 100644 src/systemd/src/basic/parse-util.c create mode 100644 src/systemd/src/basic/parse-util.h create mode 100644 src/systemd/src/basic/path-util.c create mode 100644 src/systemd/src/basic/path-util.h create mode 100644 src/systemd/src/basic/prioq.c create mode 100644 src/systemd/src/basic/prioq.h create mode 100644 src/systemd/src/basic/random-util.c create mode 100644 src/systemd/src/basic/random-util.h create mode 100644 src/systemd/src/basic/refcnt.h create mode 100644 src/systemd/src/basic/set.h create mode 100644 src/systemd/src/basic/siphash24.c create mode 100644 src/systemd/src/basic/siphash24.h create mode 100644 src/systemd/src/basic/socket-util.h create mode 100644 src/systemd/src/basic/sparse-endian.h create mode 100644 src/systemd/src/basic/string-table.c create mode 100644 src/systemd/src/basic/string-table.h create mode 100644 src/systemd/src/basic/string-util.c create mode 100644 src/systemd/src/basic/string-util.h create mode 100644 src/systemd/src/basic/strv.c create mode 100644 src/systemd/src/basic/strv.h create mode 100644 src/systemd/src/basic/time-util.c create mode 100644 src/systemd/src/basic/time-util.h create mode 100644 src/systemd/src/basic/umask-util.h create mode 100644 src/systemd/src/basic/unaligned.h create mode 100644 src/systemd/src/basic/utf8.c create mode 100644 src/systemd/src/basic/utf8.h create mode 100644 src/systemd/src/basic/util.c create mode 100644 src/systemd/src/basic/util.h create mode 100644 src/systemd/src/libsystemd-network/arp-util.c create mode 100644 src/systemd/src/libsystemd-network/arp-util.h create mode 100644 src/systemd/src/libsystemd-network/dhcp-identifier.c create mode 100644 src/systemd/src/libsystemd-network/dhcp-identifier.h create mode 100644 src/systemd/src/libsystemd-network/dhcp-internal.h create mode 100644 src/systemd/src/libsystemd-network/dhcp-lease-internal.h create mode 100644 src/systemd/src/libsystemd-network/dhcp-network.c create mode 100644 src/systemd/src/libsystemd-network/dhcp-option.c create mode 100644 src/systemd/src/libsystemd-network/dhcp-packet.c create mode 100644 src/systemd/src/libsystemd-network/dhcp-protocol.h create mode 100644 src/systemd/src/libsystemd-network/dhcp6-internal.h create mode 100644 src/systemd/src/libsystemd-network/dhcp6-lease-internal.h create mode 100644 src/systemd/src/libsystemd-network/dhcp6-network.c create mode 100644 src/systemd/src/libsystemd-network/dhcp6-option.c create mode 100644 src/systemd/src/libsystemd-network/dhcp6-protocol.h create mode 100644 src/systemd/src/libsystemd-network/lldp-internal.c create mode 100644 src/systemd/src/libsystemd-network/lldp-internal.h create mode 100644 src/systemd/src/libsystemd-network/lldp-network.c create mode 100644 src/systemd/src/libsystemd-network/lldp-network.h create mode 100644 src/systemd/src/libsystemd-network/lldp-port.c create mode 100644 src/systemd/src/libsystemd-network/lldp-port.h create mode 100644 src/systemd/src/libsystemd-network/lldp-tlv.c create mode 100644 src/systemd/src/libsystemd-network/lldp-tlv.h create mode 100644 src/systemd/src/libsystemd-network/lldp.h create mode 100644 src/systemd/src/libsystemd-network/network-internal.c create mode 100644 src/systemd/src/libsystemd-network/network-internal.h create mode 100644 src/systemd/src/libsystemd-network/sd-dhcp-client.c create mode 100644 src/systemd/src/libsystemd-network/sd-dhcp-lease.c create mode 100644 src/systemd/src/libsystemd-network/sd-dhcp6-client.c create mode 100644 src/systemd/src/libsystemd-network/sd-dhcp6-lease.c create mode 100644 src/systemd/src/libsystemd-network/sd-ipv4acd.c create mode 100644 src/systemd/src/libsystemd-network/sd-ipv4ll.c create mode 100644 src/systemd/src/libsystemd-network/sd-lldp.c create mode 100644 src/systemd/src/libsystemd/sd-id128/sd-id128.c create mode 100644 src/systemd/src/shared/dns-domain.c create mode 100644 src/systemd/src/shared/dns-domain.h create mode 100644 src/systemd/src/systemd/_sd-common.h create mode 100644 src/systemd/src/systemd/sd-dhcp-client.h create mode 100644 src/systemd/src/systemd/sd-dhcp-lease.h create mode 100644 src/systemd/src/systemd/sd-dhcp6-client.h create mode 100644 src/systemd/src/systemd/sd-dhcp6-lease.h create mode 100644 src/systemd/src/systemd/sd-event.h create mode 100644 src/systemd/src/systemd/sd-id128.h create mode 100644 src/systemd/src/systemd/sd-ipv4acd.h create mode 100644 src/systemd/src/systemd/sd-ipv4ll.h create mode 100644 src/systemd/src/systemd/sd-lldp.h create mode 100644 src/systemd/src/systemd/sd-ndisc.h create mode 100644 src/tests/config/conf.d/20-config-enable-1.conf create mode 100644 src/tests/config/global-dns-invalid.conf create mode 100644 src/tests/test-utils.c delete mode 100644 src/vpn-manager/nm-vpn-service.c delete mode 100644 src/vpn-manager/nm-vpn-service.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index e8279e77..7e858310 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,27 +2,21 @@ include $(GLIB_MAKEFILE) @GNOME_CODE_COVERAGE_RULES@ -SUBDIRS = \ - . \ - devices/adsl \ - dhcp-manager \ - ppp-manager \ - settings/plugins +SUBDIRS = \ + . \ + dhcp-manager \ + ppp-manager \ + settings/plugins \ + devices/adsl if WITH_MODEM_MANAGER_1 -SUBDIRS += \ - devices/wwan \ - devices/bluetooth +SUBDIRS += devices/wwan devices/bluetooth endif if WITH_WIFI SUBDIRS += devices/wifi endif -if WITH_WIMAX -SUBDIRS += devices/wimax -endif - if WITH_TEAMDCTL SUBDIRS += devices/team endif @@ -32,20 +26,22 @@ SUBDIRS += \ dhcp-manager/tests \ dnsmasq-manager/tests \ platform \ + devices \ rdisc \ supplicant-manager/tests \ tests endif AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ + -I$(top_builddir)/introspection \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -I$(top_srcdir)/callouts \ -DPREFIX=\"$(prefix)\" \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE # add each subdirectory that contains a libNM source file. $(sort) is being used @@ -55,74 +51,134 @@ AM_CPPFLAGS += $(foreach d,$(sort $(dir $(libNetworkManager_la_SOURCES))),-I$(to noinst_LTLIBRARIES = \ libNetworkManager.la \ libnm-iface-helper.la \ - libsystemd-dhcp.la + libsystemd-nm.la ###################### -# libsystemd-dhcp +# libsystemd-nm ###################### -SYSTEMD_DHCP_CFLAGS = \ - -I$(top_srcdir)/src/dhcp-manager/systemd-dhcp/src/systemd \ - -I$(top_srcdir)/src/dhcp-manager/systemd-dhcp/src/libsystemd-network \ - -I$(top_srcdir)/src/dhcp-manager/systemd-dhcp/src/shared \ - -I$(top_srcdir)/src/dhcp-manager/systemd-dhcp - -libsystemd_dhcp_la_SOURCES = \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-internal.h \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-network.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-lease-internal.h \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-option.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-protocol.h \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-internal.h \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-protocol.h \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c \ - dhcp-manager/systemd-dhcp/src/shared/async.h \ - dhcp-manager/systemd-dhcp/src/shared/time-util.h \ - dhcp-manager/systemd-dhcp/src/shared/siphash24.h \ - dhcp-manager/systemd-dhcp/src/shared/time-util.c \ - dhcp-manager/systemd-dhcp/src/shared/socket-util.h \ - dhcp-manager/systemd-dhcp/src/shared/sparse-endian.h \ - dhcp-manager/systemd-dhcp/src/shared/macro.h \ - dhcp-manager/systemd-dhcp/src/shared/refcnt.h \ - dhcp-manager/systemd-dhcp/src/shared/util.c \ - dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c \ - dhcp-manager/systemd-dhcp/src/shared/siphash24.c \ - dhcp-manager/systemd-dhcp/src/shared/util.h \ - dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h \ - dhcp-manager/systemd-dhcp/src/shared/list.h \ - dhcp-manager/systemd-dhcp/src/shared/fileio.h \ - dhcp-manager/systemd-dhcp/src/shared/fileio.c \ - dhcp-manager/systemd-dhcp/src/shared/strv.h \ - dhcp-manager/systemd-dhcp/src/shared/strv.c \ - dhcp-manager/systemd-dhcp/src/shared/unaligned.h \ - dhcp-manager/systemd-dhcp/src/shared/utf8.h \ - dhcp-manager/systemd-dhcp/src/shared/utf8.c \ - dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-lease.h \ - dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-client.h \ - dhcp-manager/systemd-dhcp/src/systemd/sd-id128.h \ - dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-lease.h \ - dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h \ - dhcp-manager/systemd-dhcp/src/systemd/sd-event.h \ - dhcp-manager/systemd-dhcp/src/systemd/_sd-common.h \ - dhcp-manager/systemd-dhcp/nm-sd-adapt.h \ - dhcp-manager/systemd-dhcp/nm-sd-adapt.c - -libsystemd_dhcp_la_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ - $(SYSTEMD_DHCP_CFLAGS) \ +SYSTEMD_NM_CFLAGS_PATHS = \ + -I$(top_srcdir)/src/systemd/src/systemd \ + -I$(top_srcdir)/src/systemd/src/libsystemd-network \ + -I$(top_srcdir)/src/systemd/src/basic \ + -I$(top_srcdir)/src/systemd + +libsystemd_nm_la_SOURCES = \ + systemd/nm-sd-adapt.c \ + systemd/nm-sd-adapt.h \ + systemd/src/basic/alloc-util.c \ + systemd/src/basic/alloc-util.h \ + systemd/src/basic/async.h \ + systemd/src/basic/escape.c \ + systemd/src/basic/escape.h \ + systemd/src/basic/fd-util.c \ + systemd/src/basic/fd-util.h \ + systemd/src/basic/fileio.c \ + systemd/src/basic/fileio.h \ + systemd/src/basic/fs-util.c \ + systemd/src/basic/fs-util.h \ + systemd/src/basic/hashmap.c \ + systemd/src/basic/hashmap.h \ + systemd/src/basic/hexdecoct.c \ + systemd/src/basic/hexdecoct.h \ + systemd/src/basic/hostname-util.c \ + systemd/src/basic/hostname-util.h \ + systemd/src/basic/in-addr-util.c \ + systemd/src/basic/in-addr-util.h \ + systemd/src/basic/io-util.c \ + systemd/src/basic/io-util.h \ + systemd/src/basic/list.h \ + systemd/src/basic/log.h \ + systemd/src/basic/macro.h \ + systemd/src/basic/mempool.c \ + systemd/src/basic/mempool.h \ + systemd/src/basic/parse-util.c \ + systemd/src/basic/parse-util.h \ + systemd/src/basic/path-util.c \ + systemd/src/basic/path-util.h \ + systemd/src/basic/prioq.c \ + systemd/src/basic/prioq.h \ + systemd/src/basic/random-util.c \ + systemd/src/basic/random-util.h \ + systemd/src/basic/refcnt.h \ + systemd/src/basic/siphash24.c \ + systemd/src/basic/siphash24.h \ + systemd/src/basic/set.h \ + systemd/src/basic/socket-util.h \ + systemd/src/basic/sparse-endian.h \ + systemd/src/basic/string-table.c \ + systemd/src/basic/string-table.h \ + systemd/src/basic/string-util.c \ + systemd/src/basic/string-util.h \ + systemd/src/basic/strv.c \ + systemd/src/basic/strv.h \ + systemd/src/basic/time-util.c \ + systemd/src/basic/time-util.h \ + systemd/src/basic/umask-util.h \ + systemd/src/basic/unaligned.h \ + systemd/src/basic/utf8.c \ + systemd/src/basic/utf8.h \ + systemd/src/basic/util.c \ + systemd/src/basic/util.h \ + systemd/src/libsystemd-network/arp-util.c \ + systemd/src/libsystemd-network/arp-util.h \ + systemd/src/libsystemd-network/dhcp-identifier.c \ + systemd/src/libsystemd-network/dhcp-identifier.h \ + systemd/src/libsystemd-network/dhcp-internal.h \ + systemd/src/libsystemd-network/dhcp-lease-internal.h \ + systemd/src/libsystemd-network/dhcp-network.c \ + systemd/src/libsystemd-network/dhcp-option.c \ + systemd/src/libsystemd-network/dhcp-packet.c \ + systemd/src/libsystemd-network/dhcp-protocol.h \ + systemd/src/libsystemd-network/dhcp6-internal.h \ + systemd/src/libsystemd-network/dhcp6-lease-internal.h \ + systemd/src/libsystemd-network/dhcp6-network.c \ + systemd/src/libsystemd-network/dhcp6-option.c \ + systemd/src/libsystemd-network/dhcp6-protocol.h \ + systemd/src/libsystemd-network/lldp.h \ + systemd/src/libsystemd-network/lldp-network.h \ + systemd/src/libsystemd-network/lldp-network.c \ + systemd/src/libsystemd-network/lldp-tlv.c \ + systemd/src/libsystemd-network/lldp-tlv.h \ + systemd/src/libsystemd-network/lldp-port.c \ + systemd/src/libsystemd-network/lldp-port.h \ + systemd/src/libsystemd-network/lldp-internal.h \ + systemd/src/libsystemd-network/lldp-internal.c \ + systemd/src/libsystemd-network/network-internal.c \ + systemd/src/libsystemd-network/network-internal.h \ + systemd/src/libsystemd-network/sd-dhcp-client.c \ + systemd/src/libsystemd-network/sd-dhcp-lease.c \ + systemd/src/libsystemd-network/sd-dhcp6-client.c \ + systemd/src/libsystemd-network/sd-dhcp6-lease.c \ + systemd/src/libsystemd-network/sd-ipv4acd.c \ + systemd/src/libsystemd-network/sd-ipv4ll.c \ + systemd/src/libsystemd-network/sd-lldp.c \ + systemd/src/libsystemd/sd-id128/sd-id128.c \ + systemd/src/shared/dns-domain.c \ + systemd/src/shared/dns-domain.h \ + systemd/src/systemd/_sd-common.h \ + systemd/src/systemd/sd-dhcp-client.h \ + systemd/src/systemd/sd-dhcp-lease.h \ + systemd/src/systemd/sd-dhcp6-client.h \ + systemd/src/systemd/sd-dhcp6-lease.h \ + systemd/src/systemd/sd-lldp.h \ + systemd/src/systemd/sd-event.h \ + systemd/src/systemd/sd-id128.h \ + systemd/src/systemd/sd-ipv4acd.h \ + systemd/src/systemd/sd-ipv4ll.h \ + systemd/src/systemd/sd-ndisc.h + +libsystemd_nm_la_CPPFLAGS = \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ + -I$(top_srcdir)/libnm-core \ + -I$(top_builddir)/libnm-core \ + $(SYSTEMD_NM_CFLAGS_PATHS) \ + -I$(top_srcdir)/src/systemd/src/shared \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_SYSTEMD \ $(GLIB_CFLAGS) -libsystemd_dhcp_la_LIBADD = \ +libsystemd_nm_la_LIBADD = \ $(GLIB_LIBS) ########################################### @@ -144,8 +200,8 @@ nm_device_sources = \ devices/nm-device-bond.c \ devices/nm-device-bridge.c \ devices/nm-device-ethernet.c \ - devices/nm-device-gre.c \ devices/nm-device-infiniband.c \ + devices/nm-device-ip-tunnel.c \ devices/nm-device-macvlan.c \ devices/nm-device-tun.c \ devices/nm-device-veth.c \ @@ -157,8 +213,8 @@ nm_device_headers = \ devices/nm-device-bond.h \ devices/nm-device-bridge.h \ devices/nm-device-ethernet.h \ - devices/nm-device-gre.h \ devices/nm-device-infiniband.h \ + devices/nm-device-ip-tunnel.h \ devices/nm-device-macvlan.h \ devices/nm-device-tun.h \ devices/nm-device-veth.h \ @@ -177,11 +233,13 @@ nm_dhcp_client_headers = \ dhcp-manager/nm-dhcp-dhcpcd.h \ dhcp-manager/nm-dhcp-systemd.h -nm_sources = \ +libNetworkManager_la_SOURCES = \ $(nm_device_headers) \ $(nm_dhcp_client_headers) \ devices/nm-device.c \ devices/nm-device.h \ + devices/nm-lldp-listener.c \ + devices/nm-lldp-listener.h \ devices/nm-device-ethernet-utils.c \ devices/nm-device-ethernet-utils.h \ devices/nm-device-factory.c \ @@ -252,12 +310,11 @@ nm_sources = \ settings/nm-secret-agent.h \ settings/nm-settings-connection.c \ settings/nm-settings-connection.h \ + settings/nm-settings-plugin.c \ + settings/nm-settings-plugin.h \ settings/nm-settings.c \ settings/nm-settings.h \ - settings/nm-system-config-interface.c \ - settings/nm-system-config-interface.h \ \ - settings/plugins/keyfile/common.h \ settings/plugins/keyfile/nm-keyfile-connection.c \ settings/plugins/keyfile/nm-keyfile-connection.h \ settings/plugins/keyfile/plugin.c \ @@ -283,13 +340,15 @@ nm_sources = \ vpn-manager/nm-vpn-connection.h \ vpn-manager/nm-vpn-manager.c \ vpn-manager/nm-vpn-manager.h \ - vpn-manager/nm-vpn-service.c \ - vpn-manager/nm-vpn-service.h \ \ nm-activation-request.c \ nm-activation-request.h \ nm-active-connection.c \ nm-active-connection.h \ + nm-audit-manager.c \ + nm-audit-manager.h \ + nm-bus-manager.c \ + nm-bus-manager.h \ nm-config.c \ nm-config.h \ nm-config-data.c \ @@ -298,8 +357,6 @@ nm_sources = \ nm-connection-provider.h \ nm-connectivity.c \ nm-connectivity.h \ - nm-dbus-manager.c \ - nm-dbus-manager.h \ nm-dcb.c \ nm-dcb.h \ nm-route-manager.c \ @@ -314,6 +371,8 @@ nm_sources = \ nm-dispatcher.h \ nm-enum-types.c \ nm-enum-types.h \ + nm-exported-object.c \ + nm-exported-object.h \ nm-firewall-manager.c \ nm-firewall-manager.h \ nm-ip4-config.c \ @@ -334,37 +393,25 @@ nm_sources = \ nm-multi-index.h \ nm-policy.c \ nm-policy.h \ - nm-properties-changed-signal.c \ - nm-properties-changed-signal.h \ nm-rfkill-manager.c \ nm-rfkill-manager.h \ nm-session-monitor.h \ - nm-session-utils.c \ - nm-session-utils.h \ + nm-session-monitor.c \ nm-sleep-monitor.h \ nm-types.h \ NetworkManagerUtils.c \ NetworkManagerUtils.h -if SESSION_TRACKING_SYSTEMD -nm_sources += nm-session-monitor-systemd.c -else -if SESSION_TRACKING_CK -nm_sources += nm-session-monitor-ck.c -else -nm_sources += nm-session-monitor-null.c -endif -endif -if SUSPEND_RESUME_SYSTEMD -nm_sources += nm-sleep-monitor-systemd.c +if SUSPEND_RESUME_UPOWER +libNetworkManager_la_SOURCES += nm-sleep-monitor-upower.c else -# UPower suspend/resume used whenever systemd is not enabled -nm_sources += nm-sleep-monitor-upower.c +# systemd/consolekit suspend/resume used whenever upower is not enabled +libNetworkManager_la_SOURCES += nm-sleep-monitor-systemd.c endif if WITH_WEXT -nm_sources += \ +libNetworkManager_la_SOURCES += \ platform/wifi/wifi-utils-wext.c \ platform/wifi/wifi-utils-wext.h endif @@ -373,62 +420,31 @@ endif GLIB_GENERATED = nm-enum-types.h nm-enum-types.c GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM --fhead '\#include \n' GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM -nm_enum_types_sources = $(nm_sources) - -if WITH_WIMAX -nm_enum_types_sources += devices/wimax/nm-device-wimax.h -AM_CPPFLAGS += -I$(top_srcdir)/src/devices/wimax -endif +nm_enum_types_sources = $(filter-out \ + %/nm-device-private.h \ + %/nm-rdisc-private.h \ + %/wifi-utils-private.h \ + , $(libNetworkManager_la_SOURCES)) BUILT_SOURCES = $(GLIB_GENERATED) - -glue_sources = \ - nm-access-point-glue.h \ - nm-active-connection-glue.h \ - nm-agent-manager-glue.h \ - nm-device-bond-glue.h \ - nm-device-bridge-glue.h \ - nm-device-ethernet-glue.h \ - nm-device-generic-glue.h \ - nm-device-glue.h \ - nm-device-gre-glue.h \ - nm-device-infiniband-glue.h \ - nm-device-macvlan-glue.h \ - nm-device-tun-glue.h \ - nm-device-veth-glue.h \ - nm-device-vlan-glue.h \ - nm-device-vxlan-glue.h \ - nm-dhcp4-config-glue.h \ - nm-dhcp6-config-glue.h \ - nm-ip4-config-glue.h \ - nm-ip6-config-glue.h \ - nm-manager-glue.h \ - nm-ppp-manager-glue.h \ - nm-settings-connection-glue.h \ - nm-settings-glue.h \ - nm-vpn-connection-glue.h - -BUILT_SOURCES += $(glue_sources) - -%-glue.h: $(top_srcdir)/introspection/%.xml - $(AM_V_GEN) dbus-binding-tool --prefix=$(subst -,_,$(subst -glue.h,,$@)) --mode=glib-server --output=$@ $< - - AM_CPPFLAGS += \ - $(DBUS_CFLAGS) \ $(GLIB_CFLAGS) \ $(GUDEV_CFLAGS) \ $(LIBNL_CFLAGS) \ $(LIBNDP_CFLAGS) \ $(LIBSOUP_CFLAGS) \ + $(SELINUX_CFLAGS) \ + $(LIBAUDIT_CFLAGS) \ $(SYSTEMD_LOGIN_CFLAGS) \ - $(SYSTEMD_DHCP_CFLAGS) \ + $(SYSTEMD_JOURNAL_CFLAGS) \ + $(SYSTEMD_NM_CFLAGS_PATHS) \ \ -DBINDIR=\"$(bindir)\" \ -DDATADIR=\"$(datadir)\" \ -DLIBEXECDIR=\"$(libexecdir)\" \ -DLOCALSTATEDIR=\"$(localstatedir)\" \ + -DRUNSTATEDIR=\"$(runstatedir)\" \ -DSBINDIR=\"$(sbindir)\" \ -DSYSCONFDIR=\"$(sysconfdir)\" \ -DRUNDIR=\"$(rundir)\" \ @@ -438,6 +454,7 @@ AM_CPPFLAGS += \ -DNMPLUGINDIR=\"$(pkglibdir)\" \ -DNMRUNDIR=\"$(nmrundir)\" \ -DNMSTATEDIR=\"$(nmstatedir)\" \ + -DNMLIBDIR=\"$(nmlibdir)\" \ \ -DDHCLIENT_PATH=\"$(DHCLIENT_PATH)\" \ -DDHCPCD_PATH=\"$(DHCPCD_PATH)\" \ @@ -445,25 +462,20 @@ AM_CPPFLAGS += \ \ $(NULL) -if SESSION_TRACKING_CK -AM_CPPFLAGS += -DCKDB_PATH=\"${CKDB_PATH}\" -endif - -libNetworkManager_la_SOURCES = \ - $(nm_sources) \ - $(glue_sources) - libNetworkManager_la_LIBADD = \ $(top_builddir)/libnm-core/libnm-core.la \ - libsystemd-dhcp.la \ - $(DBUS_LIBS) \ + $(top_builddir)/introspection/libnmdbus.la \ + libsystemd-nm.la \ $(GLIB_LIBS) \ $(GUDEV_LIBS) \ $(LIBNL_LIBS) \ $(SYSTEMD_LOGIN_LIBS) \ + $(SYSTEMD_JOURNAL_LIBS) \ $(LIBNDP_LIBS) \ $(LIBDL) \ - $(LIBM) + $(LIBM) \ + $(SELINUX_LIBS) \ + $(LIBAUDIT_LIBS) if WITH_LIBSOUP libNetworkManager_la_LIBADD += $(LIBSOUP_LIBS) @@ -505,6 +517,8 @@ libnm_iface_helper_la_SOURCES = \ nm-route-manager.c \ nm-route-manager.h \ \ + nm-exported-object.c \ + nm-exported-object.h \ nm-ip4-config.c \ nm-ip4-config.h \ nm-ip6-config.c \ @@ -527,8 +541,8 @@ endif libnm_iface_helper_la_LIBADD = \ $(top_builddir)/libnm-core/libnm-core.la \ - libsystemd-dhcp.la \ - $(DBUS_LIBS) \ + $(top_builddir)/introspection/libnmdbus.la \ + libsystemd-nm.la \ $(GLIB_LIBS) \ $(GUDEV_LIBS) \ $(LIBNL_LIBS) \ @@ -547,11 +561,11 @@ nm_iface_helper_SOURCES = \ nm_iface_helper_LDADD = \ $(top_builddir)/libnm-core/libnm-core.la \ - libsystemd-dhcp.la \ + libsystemd-nm.la \ libnm-iface-helper.la \ - $(DBUS_LIBS) \ $(GLIB_LIBS) \ $(GUDEV_LIBS) \ + $(SYSTEMD_JOURNAL_LIBS) \ $(LIBNL_LIBS) \ $(LIBNDP_LIBS) \ $(LIBM) @@ -567,7 +581,7 @@ EXTRA_DIST = \ $(dbusservice_DATA) \ $(NetworkManager_DATA) -rundir=$(localstatedir)/run/NetworkManager +rundir=$(runstatedir)/NetworkManager statedir=$(localstatedir)/lib/NetworkManager install-data-hook: $(mkinstalldirs) -m 0700 $(DESTDIR)$(rundir) @@ -575,8 +589,4 @@ install-data-hook: $(mkinstalldirs) -m 0755 $(DESTDIR)$(pkglibdir) CLEANFILES = \ - $(BUILT_SOURCES) \ - settings/*-glue.h \ - devices/*-glue.h \ - devices/*/*-glue.h - + $(BUILT_SOURCES) diff --git a/src/Makefile.in b/src/Makefile.in index 34ba856c..9a91cfba 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -90,37 +90,28 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -@WITH_MODEM_MANAGER_1_TRUE@am__append_1 = \ -@WITH_MODEM_MANAGER_1_TRUE@ devices/wwan \ -@WITH_MODEM_MANAGER_1_TRUE@ devices/bluetooth - +@WITH_MODEM_MANAGER_1_TRUE@am__append_1 = devices/wwan devices/bluetooth @WITH_WIFI_TRUE@am__append_2 = devices/wifi -@WITH_WIMAX_TRUE@am__append_3 = devices/wimax -@WITH_TEAMDCTL_TRUE@am__append_4 = devices/team -@ENABLE_TESTS_TRUE@am__append_5 = \ +@WITH_TEAMDCTL_TRUE@am__append_3 = devices/team +@ENABLE_TESTS_TRUE@am__append_4 = \ @ENABLE_TESTS_TRUE@ dhcp-manager/tests \ @ENABLE_TESTS_TRUE@ dnsmasq-manager/tests \ @ENABLE_TESTS_TRUE@ platform \ +@ENABLE_TESTS_TRUE@ devices \ @ENABLE_TESTS_TRUE@ rdisc \ @ENABLE_TESTS_TRUE@ supplicant-manager/tests \ @ENABLE_TESTS_TRUE@ tests sbin_PROGRAMS = NetworkManager$(EXEEXT) -@SESSION_TRACKING_SYSTEMD_TRUE@am__append_6 = nm-session-monitor-systemd.c -@SESSION_TRACKING_CK_TRUE@@SESSION_TRACKING_SYSTEMD_FALSE@am__append_7 = nm-session-monitor-ck.c -@SESSION_TRACKING_CK_FALSE@@SESSION_TRACKING_SYSTEMD_FALSE@am__append_8 = nm-session-monitor-null.c -@SUSPEND_RESUME_SYSTEMD_TRUE@am__append_9 = nm-sleep-monitor-systemd.c -# UPower suspend/resume used whenever systemd is not enabled -@SUSPEND_RESUME_SYSTEMD_FALSE@am__append_10 = nm-sleep-monitor-upower.c -@WITH_WEXT_TRUE@am__append_11 = \ +@SUSPEND_RESUME_UPOWER_TRUE@am__append_5 = nm-sleep-monitor-upower.c +# systemd/consolekit suspend/resume used whenever upower is not enabled +@SUSPEND_RESUME_UPOWER_FALSE@am__append_6 = nm-sleep-monitor-systemd.c +@WITH_WEXT_TRUE@am__append_7 = \ @WITH_WEXT_TRUE@ platform/wifi/wifi-utils-wext.c \ @WITH_WEXT_TRUE@ platform/wifi/wifi-utils-wext.h -@WITH_WIMAX_TRUE@am__append_12 = devices/wimax/nm-device-wimax.h -@WITH_WIMAX_TRUE@am__append_13 = -I$(top_srcdir)/src/devices/wimax -@SESSION_TRACKING_CK_TRUE@am__append_14 = -DCKDB_PATH=\"${CKDB_PATH}\" -@WITH_LIBSOUP_TRUE@am__append_15 = $(LIBSOUP_LIBS) -@WITH_WEXT_TRUE@am__append_16 = \ +@WITH_LIBSOUP_TRUE@am__append_8 = $(LIBSOUP_LIBS) +@WITH_WEXT_TRUE@am__append_9 = \ @WITH_WEXT_TRUE@ platform/wifi/wifi-utils-wext.c \ @WITH_WEXT_TRUE@ platform/wifi/wifi-utils-wext.h @@ -151,7 +142,9 @@ LTLIBRARIES = $(noinst_LTLIBRARIES) am__DEPENDENCIES_1 = @WITH_LIBSOUP_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) libNetworkManager_la_DEPENDENCIES = \ - $(top_builddir)/libnm-core/libnm-core.la libsystemd-dhcp.la \ + $(top_builddir)/libnm-core/libnm-core.la \ + $(top_builddir)/introspection/libnmdbus.la libsystemd-nm.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @@ -159,13 +152,14 @@ libNetworkManager_la_DEPENDENCIES = \ $(am__DEPENDENCIES_2) am__libNetworkManager_la_SOURCES_DIST = devices/nm-device-bond.h \ devices/nm-device-bridge.h devices/nm-device-ethernet.h \ - devices/nm-device-gre.h devices/nm-device-infiniband.h \ + devices/nm-device-infiniband.h devices/nm-device-ip-tunnel.h \ devices/nm-device-macvlan.h devices/nm-device-tun.h \ devices/nm-device-veth.h devices/nm-device-vlan.h \ devices/nm-device-vxlan.h dhcp-manager/nm-dhcp-dhclient.h \ dhcp-manager/nm-dhcp-dhclient-utils.h \ dhcp-manager/nm-dhcp-dhcpcd.h dhcp-manager/nm-dhcp-systemd.h \ devices/nm-device.c devices/nm-device.h \ + devices/nm-lldp-listener.c devices/nm-lldp-listener.h \ devices/nm-device-ethernet-utils.c \ devices/nm-device-ethernet-utils.h devices/nm-device-factory.c \ devices/nm-device-factory.h devices/nm-device-generic.c \ @@ -200,10 +194,9 @@ am__libNetworkManager_la_SOURCES_DIST = devices/nm-device-bond.h \ settings/nm-inotify-helper.c settings/nm-inotify-helper.h \ settings/nm-secret-agent.c settings/nm-secret-agent.h \ settings/nm-settings-connection.c \ - settings/nm-settings-connection.h settings/nm-settings.c \ - settings/nm-settings.h settings/nm-system-config-interface.c \ - settings/nm-system-config-interface.h \ - settings/plugins/keyfile/common.h \ + settings/nm-settings-connection.h \ + settings/nm-settings-plugin.c settings/nm-settings-plugin.h \ + settings/nm-settings.c settings/nm-settings.h \ settings/plugins/keyfile/nm-keyfile-connection.c \ settings/plugins/keyfile/nm-keyfile-connection.h \ settings/plugins/keyfile/plugin.c \ @@ -225,93 +218,74 @@ am__libNetworkManager_la_SOURCES_DIST = devices/nm-device-bond.h \ supplicant-manager/nm-supplicant-types.h \ vpn-manager/nm-vpn-connection.c \ vpn-manager/nm-vpn-connection.h vpn-manager/nm-vpn-manager.c \ - vpn-manager/nm-vpn-manager.h vpn-manager/nm-vpn-service.c \ - vpn-manager/nm-vpn-service.h nm-activation-request.c \ + vpn-manager/nm-vpn-manager.h nm-activation-request.c \ nm-activation-request.h nm-active-connection.c \ - nm-active-connection.h nm-config.c nm-config.h \ + nm-active-connection.h nm-audit-manager.c nm-audit-manager.h \ + nm-bus-manager.c nm-bus-manager.h nm-config.c nm-config.h \ nm-config-data.c nm-config-data.h nm-connection-provider.c \ nm-connection-provider.h nm-connectivity.c nm-connectivity.h \ - nm-dbus-manager.c nm-dbus-manager.h nm-dcb.c nm-dcb.h \ - nm-route-manager.c nm-route-manager.h \ + nm-dcb.c nm-dcb.h nm-route-manager.c nm-route-manager.h \ nm-default-route-manager.c nm-default-route-manager.h \ nm-dhcp4-config.c nm-dhcp4-config.h nm-dhcp6-config.c \ nm-dhcp6-config.h nm-dispatcher.c nm-dispatcher.h \ - nm-enum-types.c nm-enum-types.h nm-firewall-manager.c \ + nm-enum-types.c nm-enum-types.h nm-exported-object.c \ + nm-exported-object.h nm-firewall-manager.c \ nm-firewall-manager.h nm-ip4-config.c nm-ip4-config.h \ nm-ip6-config.c nm-ip6-config.h nm-logging.c nm-logging.h \ nm-auth-manager.c nm-auth-manager.h nm-auth-subject.c \ nm-auth-subject.h nm-auth-utils.c nm-auth-utils.h nm-manager.c \ nm-manager.h nm-multi-index.c nm-multi-index.h nm-policy.c \ - nm-policy.h nm-properties-changed-signal.c \ - nm-properties-changed-signal.h nm-rfkill-manager.c \ - nm-rfkill-manager.h nm-session-monitor.h nm-session-utils.c \ - nm-session-utils.h nm-sleep-monitor.h nm-types.h \ - NetworkManagerUtils.c NetworkManagerUtils.h \ - nm-session-monitor-systemd.c nm-session-monitor-ck.c \ - nm-session-monitor-null.c nm-sleep-monitor-systemd.c \ - nm-sleep-monitor-upower.c platform/wifi/wifi-utils-wext.c \ - platform/wifi/wifi-utils-wext.h nm-access-point-glue.h \ - nm-active-connection-glue.h nm-agent-manager-glue.h \ - nm-device-bond-glue.h nm-device-bridge-glue.h \ - nm-device-ethernet-glue.h nm-device-generic-glue.h \ - nm-device-glue.h nm-device-gre-glue.h \ - nm-device-infiniband-glue.h nm-device-macvlan-glue.h \ - nm-device-tun-glue.h nm-device-veth-glue.h \ - nm-device-vlan-glue.h nm-device-vxlan-glue.h \ - nm-dhcp4-config-glue.h nm-dhcp6-config-glue.h \ - nm-ip4-config-glue.h nm-ip6-config-glue.h nm-manager-glue.h \ - nm-ppp-manager-glue.h nm-settings-connection-glue.h \ - nm-settings-glue.h nm-vpn-connection-glue.h + nm-policy.h nm-rfkill-manager.c nm-rfkill-manager.h \ + nm-session-monitor.h nm-session-monitor.c nm-sleep-monitor.h \ + nm-types.h NetworkManagerUtils.c NetworkManagerUtils.h \ + nm-sleep-monitor-upower.c nm-sleep-monitor-systemd.c \ + platform/wifi/wifi-utils-wext.c \ + platform/wifi/wifi-utils-wext.h am__objects_1 = -@SESSION_TRACKING_SYSTEMD_TRUE@am__objects_2 = \ -@SESSION_TRACKING_SYSTEMD_TRUE@ nm-session-monitor-systemd.lo -@SESSION_TRACKING_CK_TRUE@@SESSION_TRACKING_SYSTEMD_FALSE@am__objects_3 = nm-session-monitor-ck.lo -@SESSION_TRACKING_CK_FALSE@@SESSION_TRACKING_SYSTEMD_FALSE@am__objects_4 = nm-session-monitor-null.lo -@SUSPEND_RESUME_SYSTEMD_TRUE@am__objects_5 = \ -@SUSPEND_RESUME_SYSTEMD_TRUE@ nm-sleep-monitor-systemd.lo -@SUSPEND_RESUME_SYSTEMD_FALSE@am__objects_6 = \ -@SUSPEND_RESUME_SYSTEMD_FALSE@ nm-sleep-monitor-upower.lo -@WITH_WEXT_TRUE@am__objects_7 = wifi-utils-wext.lo -am__objects_8 = $(am__objects_1) $(am__objects_1) nm-device.lo \ - nm-device-ethernet-utils.lo nm-device-factory.lo \ - nm-device-generic.lo nm-dhcp-client.lo nm-dhcp-utils.lo \ - nm-dhcp-listener.lo nm-dhcp-manager.lo nm-dns-dnsmasq.lo \ - nm-dns-unbound.lo nm-dns-manager.lo nm-dns-plugin.lo \ - nm-dns-utils.lo nm-dnsmasq-manager.lo nm-dnsmasq-utils.lo \ - nm-fake-platform.lo nm-linux-platform.lo nm-platform.lo \ - nm-platform-utils.lo nmp-object.lo wifi-utils-nl80211.lo \ - wifi-utils.lo nm-fake-rdisc.lo nm-lndp-rdisc.lo nm-rdisc.lo \ - nm-ppp-manager.lo nm-agent-manager.lo nm-inotify-helper.lo \ - nm-secret-agent.lo nm-settings-connection.lo nm-settings.lo \ - nm-system-config-interface.lo nm-keyfile-connection.lo \ - plugin.lo reader.lo utils.lo writer.lo nm-supplicant-config.lo \ - nm-supplicant-interface.lo nm-supplicant-manager.lo \ - nm-supplicant-settings-verify.lo nm-vpn-connection.lo \ - nm-vpn-manager.lo nm-vpn-service.lo nm-activation-request.lo \ - nm-active-connection.lo nm-config.lo nm-config-data.lo \ - nm-connection-provider.lo nm-connectivity.lo \ - nm-dbus-manager.lo nm-dcb.lo nm-route-manager.lo \ - nm-default-route-manager.lo nm-dhcp4-config.lo \ - nm-dhcp6-config.lo nm-dispatcher.lo nm-enum-types.lo \ - nm-firewall-manager.lo nm-ip4-config.lo nm-ip6-config.lo \ - nm-logging.lo nm-auth-manager.lo nm-auth-subject.lo \ - nm-auth-utils.lo nm-manager.lo nm-multi-index.lo nm-policy.lo \ - nm-properties-changed-signal.lo nm-rfkill-manager.lo \ - nm-session-utils.lo NetworkManagerUtils.lo $(am__objects_2) \ - $(am__objects_3) $(am__objects_4) $(am__objects_5) \ - $(am__objects_6) $(am__objects_7) -am_libNetworkManager_la_OBJECTS = $(am__objects_8) $(am__objects_1) +@SUSPEND_RESUME_UPOWER_TRUE@am__objects_2 = \ +@SUSPEND_RESUME_UPOWER_TRUE@ nm-sleep-monitor-upower.lo +@SUSPEND_RESUME_UPOWER_FALSE@am__objects_3 = \ +@SUSPEND_RESUME_UPOWER_FALSE@ nm-sleep-monitor-systemd.lo +@WITH_WEXT_TRUE@am__objects_4 = wifi-utils-wext.lo +am_libNetworkManager_la_OBJECTS = $(am__objects_1) $(am__objects_1) \ + nm-device.lo nm-lldp-listener.lo nm-device-ethernet-utils.lo \ + nm-device-factory.lo nm-device-generic.lo nm-dhcp-client.lo \ + nm-dhcp-utils.lo nm-dhcp-listener.lo nm-dhcp-manager.lo \ + nm-dns-dnsmasq.lo nm-dns-unbound.lo nm-dns-manager.lo \ + nm-dns-plugin.lo nm-dns-utils.lo nm-dnsmasq-manager.lo \ + nm-dnsmasq-utils.lo nm-fake-platform.lo nm-linux-platform.lo \ + nm-platform.lo nm-platform-utils.lo nmp-object.lo \ + wifi-utils-nl80211.lo wifi-utils.lo nm-fake-rdisc.lo \ + nm-lndp-rdisc.lo nm-rdisc.lo nm-ppp-manager.lo \ + nm-agent-manager.lo nm-inotify-helper.lo nm-secret-agent.lo \ + nm-settings-connection.lo nm-settings-plugin.lo nm-settings.lo \ + nm-keyfile-connection.lo plugin.lo reader.lo utils.lo \ + writer.lo nm-supplicant-config.lo nm-supplicant-interface.lo \ + nm-supplicant-manager.lo nm-supplicant-settings-verify.lo \ + nm-vpn-connection.lo nm-vpn-manager.lo \ + nm-activation-request.lo nm-active-connection.lo \ + nm-audit-manager.lo nm-bus-manager.lo nm-config.lo \ + nm-config-data.lo nm-connection-provider.lo nm-connectivity.lo \ + nm-dcb.lo nm-route-manager.lo nm-default-route-manager.lo \ + nm-dhcp4-config.lo nm-dhcp6-config.lo nm-dispatcher.lo \ + nm-enum-types.lo nm-exported-object.lo nm-firewall-manager.lo \ + nm-ip4-config.lo nm-ip6-config.lo nm-logging.lo \ + nm-auth-manager.lo nm-auth-subject.lo nm-auth-utils.lo \ + nm-manager.lo nm-multi-index.lo nm-policy.lo \ + nm-rfkill-manager.lo nm-session-monitor.lo \ + NetworkManagerUtils.lo $(am__objects_2) $(am__objects_3) \ + $(am__objects_4) libNetworkManager_la_OBJECTS = $(am_libNetworkManager_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libnm_iface_helper_la_DEPENDENCIES = \ - $(top_builddir)/libnm-core/libnm-core.la libsystemd-dhcp.la \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(top_builddir)/libnm-core/libnm-core.la \ + $(top_builddir)/introspection/libnmdbus.la libsystemd-nm.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am__libnm_iface_helper_la_SOURCES_DIST = \ dhcp-manager/nm-dhcp-client.c dhcp-manager/nm-dhcp-client.h \ dhcp-manager/nm-dhcp-utils.c dhcp-manager/nm-dhcp-utils.h \ @@ -326,50 +300,67 @@ am__libnm_iface_helper_la_SOURCES_DIST = \ platform/wifi/wifi-utils.h rdisc/nm-fake-rdisc.c \ rdisc/nm-fake-rdisc.h rdisc/nm-lndp-rdisc.c \ rdisc/nm-lndp-rdisc.h rdisc/nm-rdisc.c rdisc/nm-rdisc.h \ - nm-route-manager.c nm-route-manager.h nm-ip4-config.c \ - nm-ip4-config.h nm-ip6-config.c nm-ip6-config.h \ - nm-enum-types.c nm-enum-types.h nm-logging.c nm-logging.h \ - nm-multi-index.c nm-multi-index.h NetworkManagerUtils.c \ - NetworkManagerUtils.h platform/wifi/wifi-utils-wext.c \ + nm-route-manager.c nm-route-manager.h nm-exported-object.c \ + nm-exported-object.h nm-ip4-config.c nm-ip4-config.h \ + nm-ip6-config.c nm-ip6-config.h nm-enum-types.c \ + nm-enum-types.h nm-logging.c nm-logging.h nm-multi-index.c \ + nm-multi-index.h NetworkManagerUtils.c NetworkManagerUtils.h \ + platform/wifi/wifi-utils-wext.c \ platform/wifi/wifi-utils-wext.h am_libnm_iface_helper_la_OBJECTS = nm-dhcp-client.lo nm-dhcp-utils.lo \ nm-dhcp-manager.lo nm-linux-platform.lo nm-platform.lo \ nm-platform-utils.lo nmp-object.lo wifi-utils-nl80211.lo \ wifi-utils.lo nm-fake-rdisc.lo nm-lndp-rdisc.lo nm-rdisc.lo \ - nm-route-manager.lo nm-ip4-config.lo nm-ip6-config.lo \ - nm-enum-types.lo nm-logging.lo nm-multi-index.lo \ - NetworkManagerUtils.lo $(am__objects_7) + nm-route-manager.lo nm-exported-object.lo nm-ip4-config.lo \ + nm-ip6-config.lo nm-enum-types.lo nm-logging.lo \ + nm-multi-index.lo NetworkManagerUtils.lo $(am__objects_4) libnm_iface_helper_la_OBJECTS = $(am_libnm_iface_helper_la_OBJECTS) -libsystemd_dhcp_la_DEPENDENCIES = $(am__DEPENDENCIES_1) -am_libsystemd_dhcp_la_OBJECTS = libsystemd_dhcp_la-dhcp-network.lo \ - libsystemd_dhcp_la-dhcp-packet.lo \ - libsystemd_dhcp_la-dhcp6-network.lo \ - libsystemd_dhcp_la-dhcp6-option.lo \ - libsystemd_dhcp_la-network-internal.lo \ - libsystemd_dhcp_la-sd-dhcp-lease.lo \ - libsystemd_dhcp_la-sd-dhcp-client.lo \ - libsystemd_dhcp_la-dhcp-option.lo \ - libsystemd_dhcp_la-sd-dhcp6-lease.lo \ - libsystemd_dhcp_la-sd-dhcp6-client.lo \ - libsystemd_dhcp_la-time-util.lo libsystemd_dhcp_la-util.lo \ - libsystemd_dhcp_la-in-addr-util.lo \ - libsystemd_dhcp_la-siphash24.lo libsystemd_dhcp_la-fileio.lo \ - libsystemd_dhcp_la-strv.lo libsystemd_dhcp_la-utf8.lo \ - libsystemd_dhcp_la-nm-sd-adapt.lo -libsystemd_dhcp_la_OBJECTS = $(am_libsystemd_dhcp_la_OBJECTS) +libsystemd_nm_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_libsystemd_nm_la_OBJECTS = libsystemd_nm_la-nm-sd-adapt.lo \ + libsystemd_nm_la-alloc-util.lo libsystemd_nm_la-escape.lo \ + libsystemd_nm_la-fd-util.lo libsystemd_nm_la-fileio.lo \ + libsystemd_nm_la-fs-util.lo libsystemd_nm_la-hashmap.lo \ + libsystemd_nm_la-hexdecoct.lo \ + libsystemd_nm_la-hostname-util.lo \ + libsystemd_nm_la-in-addr-util.lo libsystemd_nm_la-io-util.lo \ + libsystemd_nm_la-mempool.lo libsystemd_nm_la-parse-util.lo \ + libsystemd_nm_la-path-util.lo libsystemd_nm_la-prioq.lo \ + libsystemd_nm_la-random-util.lo libsystemd_nm_la-siphash24.lo \ + libsystemd_nm_la-string-table.lo \ + libsystemd_nm_la-string-util.lo libsystemd_nm_la-strv.lo \ + libsystemd_nm_la-time-util.lo libsystemd_nm_la-utf8.lo \ + libsystemd_nm_la-util.lo libsystemd_nm_la-arp-util.lo \ + libsystemd_nm_la-dhcp-identifier.lo \ + libsystemd_nm_la-dhcp-network.lo \ + libsystemd_nm_la-dhcp-option.lo \ + libsystemd_nm_la-dhcp-packet.lo \ + libsystemd_nm_la-dhcp6-network.lo \ + libsystemd_nm_la-dhcp6-option.lo \ + libsystemd_nm_la-lldp-network.lo libsystemd_nm_la-lldp-tlv.lo \ + libsystemd_nm_la-lldp-port.lo \ + libsystemd_nm_la-lldp-internal.lo \ + libsystemd_nm_la-network-internal.lo \ + libsystemd_nm_la-sd-dhcp-client.lo \ + libsystemd_nm_la-sd-dhcp-lease.lo \ + libsystemd_nm_la-sd-dhcp6-client.lo \ + libsystemd_nm_la-sd-dhcp6-lease.lo \ + libsystemd_nm_la-sd-ipv4acd.lo libsystemd_nm_la-sd-ipv4ll.lo \ + libsystemd_nm_la-sd-lldp.lo libsystemd_nm_la-sd-id128.lo \ + libsystemd_nm_la-dns-domain.lo +libsystemd_nm_la_OBJECTS = $(am_libsystemd_nm_la_OBJECTS) am__installdirs = "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(dbusservicedir)" PROGRAMS = $(libexec_PROGRAMS) $(sbin_PROGRAMS) -am__objects_9 = nm-device-bond.$(OBJEXT) nm-device-bridge.$(OBJEXT) \ - nm-device-ethernet.$(OBJEXT) nm-device-gre.$(OBJEXT) \ - nm-device-infiniband.$(OBJEXT) nm-device-macvlan.$(OBJEXT) \ +am__objects_5 = nm-device-bond.$(OBJEXT) nm-device-bridge.$(OBJEXT) \ + nm-device-ethernet.$(OBJEXT) nm-device-infiniband.$(OBJEXT) \ + nm-device-ip-tunnel.$(OBJEXT) nm-device-macvlan.$(OBJEXT) \ nm-device-tun.$(OBJEXT) nm-device-veth.$(OBJEXT) \ nm-device-vlan.$(OBJEXT) nm-device-vxlan.$(OBJEXT) -am__objects_10 = nm-dhcp-dhclient.$(OBJEXT) \ +am__objects_6 = nm-dhcp-dhclient.$(OBJEXT) \ nm-dhcp-dhclient-utils.$(OBJEXT) nm-dhcp-dhcpcd.$(OBJEXT) \ nm-dhcp-systemd.$(OBJEXT) -am_NetworkManager_OBJECTS = $(am__objects_9) $(am__objects_1) \ - $(am__objects_10) $(am__objects_1) main-utils.$(OBJEXT) \ +am_NetworkManager_OBJECTS = $(am__objects_5) $(am__objects_1) \ + $(am__objects_6) $(am__objects_1) main-utils.$(OBJEXT) \ main.$(OBJEXT) NetworkManager_OBJECTS = $(am_NetworkManager_OBJECTS) NetworkManager_DEPENDENCIES = libNetworkManager.la @@ -381,7 +372,7 @@ am_nm_iface_helper_OBJECTS = nm-dhcp-systemd.$(OBJEXT) \ nm-iface-helper.$(OBJEXT) main-utils.$(OBJEXT) nm_iface_helper_OBJECTS = $(am_nm_iface_helper_OBJECTS) nm_iface_helper_DEPENDENCIES = \ - $(top_builddir)/libnm-core/libnm-core.la libsystemd-dhcp.la \ + $(top_builddir)/libnm-core/libnm-core.la libsystemd-nm.la \ libnm-iface-helper.la $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ @@ -425,11 +416,11 @@ am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libNetworkManager_la_SOURCES) \ - $(libnm_iface_helper_la_SOURCES) $(libsystemd_dhcp_la_SOURCES) \ + $(libnm_iface_helper_la_SOURCES) $(libsystemd_nm_la_SOURCES) \ $(NetworkManager_SOURCES) $(nm_iface_helper_SOURCES) DIST_SOURCES = $(am__libNetworkManager_la_SOURCES_DIST) \ $(am__libnm_iface_helper_la_SOURCES_DIST) \ - $(libsystemd_dhcp_la_SOURCES) $(NetworkManager_SOURCES) \ + $(libsystemd_nm_la_SOURCES) $(NetworkManager_SOURCES) \ $(nm_iface_helper_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ @@ -499,11 +490,10 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags -DIST_SUBDIRS = . devices/adsl dhcp-manager ppp-manager \ - settings/plugins devices/wwan devices/bluetooth devices/wifi \ - devices/wimax devices/team dhcp-manager/tests \ - dnsmasq-manager/tests platform rdisc supplicant-manager/tests \ - tests +DIST_SUBDIRS = . dhcp-manager ppp-manager settings/plugins \ + devices/adsl devices/wwan devices/bluetooth devices/wifi \ + devices/team dhcp-manager/tests dnsmasq-manager/tests platform \ + devices rdisc supplicant-manager/tests tests am__DIST_COMMON = $(srcdir)/Makefile.in \ $(top_srcdir)/build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -547,7 +537,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -559,8 +548,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -570,6 +557,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -624,16 +612,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -670,6 +655,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -698,7 +685,6 @@ 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@ @@ -713,6 +699,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -773,6 +761,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -780,6 +769,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -795,106 +785,167 @@ with_dhcpcd = @with_dhcpcd@ with_netconfig = @with_netconfig@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ -SUBDIRS = . devices/adsl dhcp-manager ppp-manager settings/plugins \ +SUBDIRS = . dhcp-manager ppp-manager settings/plugins devices/adsl \ $(am__append_1) $(am__append_2) $(am__append_3) \ - $(am__append_4) $(am__append_5) + $(am__append_4) # add each subdirectory that contains a libNM source file. $(sort) is being used # primarily for its side effect of removing duplicates. -AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/include \ - -I$(top_srcdir)/libnm-core -I$(top_builddir)/libnm-core \ - -I$(top_srcdir)/callouts -DPREFIX=\"$(prefix)\" \ - -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ +AM_CPPFLAGS = -I$(top_srcdir)/shared -I$(top_builddir)/shared \ + -I$(top_builddir)/introspection -I$(top_srcdir)/libnm-core \ + -I$(top_builddir)/libnm-core -I$(top_srcdir)/callouts \ + -DPREFIX=\"$(prefix)\" -DG_LOG_DOMAIN=\""NetworkManager"\" \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE $(foreach \ d,$(sort $(dir \ $(libNetworkManager_la_SOURCES))),-I$(top_srcdir)/src/$d) \ - $(am__append_13) $(DBUS_CFLAGS) $(GLIB_CFLAGS) $(GUDEV_CFLAGS) \ - $(LIBNL_CFLAGS) $(LIBNDP_CFLAGS) $(LIBSOUP_CFLAGS) \ - $(SYSTEMD_LOGIN_CFLAGS) $(SYSTEMD_DHCP_CFLAGS) \ + $(GLIB_CFLAGS) $(GUDEV_CFLAGS) $(LIBNL_CFLAGS) \ + $(LIBNDP_CFLAGS) $(LIBSOUP_CFLAGS) $(SELINUX_CFLAGS) \ + $(LIBAUDIT_CFLAGS) $(SYSTEMD_LOGIN_CFLAGS) \ + $(SYSTEMD_JOURNAL_CFLAGS) $(SYSTEMD_NM_CFLAGS_PATHS) \ -DBINDIR=\"$(bindir)\" -DDATADIR=\"$(datadir)\" \ -DLIBEXECDIR=\"$(libexecdir)\" \ - -DLOCALSTATEDIR=\"$(localstatedir)\" -DSBINDIR=\"$(sbindir)\" \ + -DLOCALSTATEDIR=\"$(localstatedir)\" \ + -DRUNSTATEDIR=\"$(runstatedir)\" -DSBINDIR=\"$(sbindir)\" \ -DSYSCONFDIR=\"$(sysconfdir)\" -DRUNDIR=\"$(rundir)\" \ -DNMCONFDIR=\"$(nmconfdir)\" \ -DNMLOCALEDIR=\"$(datadir)/locale\" \ -DNMPLUGINDIR=\"$(pkglibdir)\" -DNMRUNDIR=\"$(nmrundir)\" \ - -DNMSTATEDIR=\"$(nmstatedir)\" \ + -DNMSTATEDIR=\"$(nmstatedir)\" -DNMLIBDIR=\"$(nmlibdir)\" \ -DDHCLIENT_PATH=\"$(DHCLIENT_PATH)\" \ -DDHCPCD_PATH=\"$(DHCPCD_PATH)\" \ - -DPPPD_PLUGIN_DIR=\"$(PPPD_PLUGIN_DIR)\" $(NULL) \ - $(am__append_14) + -DPPPD_PLUGIN_DIR=\"$(PPPD_PLUGIN_DIR)\" $(NULL) noinst_LTLIBRARIES = \ libNetworkManager.la \ libnm-iface-helper.la \ - libsystemd-dhcp.la + libsystemd-nm.la ###################### -# libsystemd-dhcp +# libsystemd-nm ###################### -SYSTEMD_DHCP_CFLAGS = \ - -I$(top_srcdir)/src/dhcp-manager/systemd-dhcp/src/systemd \ - -I$(top_srcdir)/src/dhcp-manager/systemd-dhcp/src/libsystemd-network \ - -I$(top_srcdir)/src/dhcp-manager/systemd-dhcp/src/shared \ - -I$(top_srcdir)/src/dhcp-manager/systemd-dhcp - -libsystemd_dhcp_la_SOURCES = \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-internal.h \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-network.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-lease-internal.h \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-option.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-protocol.h \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-internal.h \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-protocol.h \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h \ - dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c \ - dhcp-manager/systemd-dhcp/src/shared/async.h \ - dhcp-manager/systemd-dhcp/src/shared/time-util.h \ - dhcp-manager/systemd-dhcp/src/shared/siphash24.h \ - dhcp-manager/systemd-dhcp/src/shared/time-util.c \ - dhcp-manager/systemd-dhcp/src/shared/socket-util.h \ - dhcp-manager/systemd-dhcp/src/shared/sparse-endian.h \ - dhcp-manager/systemd-dhcp/src/shared/macro.h \ - dhcp-manager/systemd-dhcp/src/shared/refcnt.h \ - dhcp-manager/systemd-dhcp/src/shared/util.c \ - dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c \ - dhcp-manager/systemd-dhcp/src/shared/siphash24.c \ - dhcp-manager/systemd-dhcp/src/shared/util.h \ - dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h \ - dhcp-manager/systemd-dhcp/src/shared/list.h \ - dhcp-manager/systemd-dhcp/src/shared/fileio.h \ - dhcp-manager/systemd-dhcp/src/shared/fileio.c \ - dhcp-manager/systemd-dhcp/src/shared/strv.h \ - dhcp-manager/systemd-dhcp/src/shared/strv.c \ - dhcp-manager/systemd-dhcp/src/shared/unaligned.h \ - dhcp-manager/systemd-dhcp/src/shared/utf8.h \ - dhcp-manager/systemd-dhcp/src/shared/utf8.c \ - dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-lease.h \ - dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-client.h \ - dhcp-manager/systemd-dhcp/src/systemd/sd-id128.h \ - dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-lease.h \ - dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h \ - dhcp-manager/systemd-dhcp/src/systemd/sd-event.h \ - dhcp-manager/systemd-dhcp/src/systemd/_sd-common.h \ - dhcp-manager/systemd-dhcp/nm-sd-adapt.h \ - dhcp-manager/systemd-dhcp/nm-sd-adapt.c - -libsystemd_dhcp_la_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ - $(SYSTEMD_DHCP_CFLAGS) \ +SYSTEMD_NM_CFLAGS_PATHS = \ + -I$(top_srcdir)/src/systemd/src/systemd \ + -I$(top_srcdir)/src/systemd/src/libsystemd-network \ + -I$(top_srcdir)/src/systemd/src/basic \ + -I$(top_srcdir)/src/systemd + +libsystemd_nm_la_SOURCES = \ + systemd/nm-sd-adapt.c \ + systemd/nm-sd-adapt.h \ + systemd/src/basic/alloc-util.c \ + systemd/src/basic/alloc-util.h \ + systemd/src/basic/async.h \ + systemd/src/basic/escape.c \ + systemd/src/basic/escape.h \ + systemd/src/basic/fd-util.c \ + systemd/src/basic/fd-util.h \ + systemd/src/basic/fileio.c \ + systemd/src/basic/fileio.h \ + systemd/src/basic/fs-util.c \ + systemd/src/basic/fs-util.h \ + systemd/src/basic/hashmap.c \ + systemd/src/basic/hashmap.h \ + systemd/src/basic/hexdecoct.c \ + systemd/src/basic/hexdecoct.h \ + systemd/src/basic/hostname-util.c \ + systemd/src/basic/hostname-util.h \ + systemd/src/basic/in-addr-util.c \ + systemd/src/basic/in-addr-util.h \ + systemd/src/basic/io-util.c \ + systemd/src/basic/io-util.h \ + systemd/src/basic/list.h \ + systemd/src/basic/log.h \ + systemd/src/basic/macro.h \ + systemd/src/basic/mempool.c \ + systemd/src/basic/mempool.h \ + systemd/src/basic/parse-util.c \ + systemd/src/basic/parse-util.h \ + systemd/src/basic/path-util.c \ + systemd/src/basic/path-util.h \ + systemd/src/basic/prioq.c \ + systemd/src/basic/prioq.h \ + systemd/src/basic/random-util.c \ + systemd/src/basic/random-util.h \ + systemd/src/basic/refcnt.h \ + systemd/src/basic/siphash24.c \ + systemd/src/basic/siphash24.h \ + systemd/src/basic/set.h \ + systemd/src/basic/socket-util.h \ + systemd/src/basic/sparse-endian.h \ + systemd/src/basic/string-table.c \ + systemd/src/basic/string-table.h \ + systemd/src/basic/string-util.c \ + systemd/src/basic/string-util.h \ + systemd/src/basic/strv.c \ + systemd/src/basic/strv.h \ + systemd/src/basic/time-util.c \ + systemd/src/basic/time-util.h \ + systemd/src/basic/umask-util.h \ + systemd/src/basic/unaligned.h \ + systemd/src/basic/utf8.c \ + systemd/src/basic/utf8.h \ + systemd/src/basic/util.c \ + systemd/src/basic/util.h \ + systemd/src/libsystemd-network/arp-util.c \ + systemd/src/libsystemd-network/arp-util.h \ + systemd/src/libsystemd-network/dhcp-identifier.c \ + systemd/src/libsystemd-network/dhcp-identifier.h \ + systemd/src/libsystemd-network/dhcp-internal.h \ + systemd/src/libsystemd-network/dhcp-lease-internal.h \ + systemd/src/libsystemd-network/dhcp-network.c \ + systemd/src/libsystemd-network/dhcp-option.c \ + systemd/src/libsystemd-network/dhcp-packet.c \ + systemd/src/libsystemd-network/dhcp-protocol.h \ + systemd/src/libsystemd-network/dhcp6-internal.h \ + systemd/src/libsystemd-network/dhcp6-lease-internal.h \ + systemd/src/libsystemd-network/dhcp6-network.c \ + systemd/src/libsystemd-network/dhcp6-option.c \ + systemd/src/libsystemd-network/dhcp6-protocol.h \ + systemd/src/libsystemd-network/lldp.h \ + systemd/src/libsystemd-network/lldp-network.h \ + systemd/src/libsystemd-network/lldp-network.c \ + systemd/src/libsystemd-network/lldp-tlv.c \ + systemd/src/libsystemd-network/lldp-tlv.h \ + systemd/src/libsystemd-network/lldp-port.c \ + systemd/src/libsystemd-network/lldp-port.h \ + systemd/src/libsystemd-network/lldp-internal.h \ + systemd/src/libsystemd-network/lldp-internal.c \ + systemd/src/libsystemd-network/network-internal.c \ + systemd/src/libsystemd-network/network-internal.h \ + systemd/src/libsystemd-network/sd-dhcp-client.c \ + systemd/src/libsystemd-network/sd-dhcp-lease.c \ + systemd/src/libsystemd-network/sd-dhcp6-client.c \ + systemd/src/libsystemd-network/sd-dhcp6-lease.c \ + systemd/src/libsystemd-network/sd-ipv4acd.c \ + systemd/src/libsystemd-network/sd-ipv4ll.c \ + systemd/src/libsystemd-network/sd-lldp.c \ + systemd/src/libsystemd/sd-id128/sd-id128.c \ + systemd/src/shared/dns-domain.c \ + systemd/src/shared/dns-domain.h \ + systemd/src/systemd/_sd-common.h \ + systemd/src/systemd/sd-dhcp-client.h \ + systemd/src/systemd/sd-dhcp-lease.h \ + systemd/src/systemd/sd-dhcp6-client.h \ + systemd/src/systemd/sd-dhcp6-lease.h \ + systemd/src/systemd/sd-lldp.h \ + systemd/src/systemd/sd-event.h \ + systemd/src/systemd/sd-id128.h \ + systemd/src/systemd/sd-ipv4acd.h \ + systemd/src/systemd/sd-ipv4ll.h \ + systemd/src/systemd/sd-ndisc.h + +libsystemd_nm_la_CPPFLAGS = \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ + -I$(top_srcdir)/libnm-core \ + -I$(top_builddir)/libnm-core \ + $(SYSTEMD_NM_CFLAGS_PATHS) \ + -I$(top_srcdir)/src/systemd/src/shared \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_SYSTEMD \ $(GLIB_CFLAGS) -libsystemd_dhcp_la_LIBADD = \ +libsystemd_nm_la_LIBADD = \ $(GLIB_LIBS) NetworkManager_SOURCES = \ @@ -909,8 +960,8 @@ nm_device_sources = \ devices/nm-device-bond.c \ devices/nm-device-bridge.c \ devices/nm-device-ethernet.c \ - devices/nm-device-gre.c \ devices/nm-device-infiniband.c \ + devices/nm-device-ip-tunnel.c \ devices/nm-device-macvlan.c \ devices/nm-device-tun.c \ devices/nm-device-veth.c \ @@ -922,8 +973,8 @@ nm_device_headers = \ devices/nm-device-bond.h \ devices/nm-device-bridge.h \ devices/nm-device-ethernet.h \ - devices/nm-device-gre.h \ devices/nm-device-infiniband.h \ + devices/nm-device-ip-tunnel.h \ devices/nm-device-macvlan.h \ devices/nm-device-tun.h \ devices/nm-device-veth.h \ @@ -942,9 +993,10 @@ nm_dhcp_client_headers = \ dhcp-manager/nm-dhcp-dhcpcd.h \ dhcp-manager/nm-dhcp-systemd.h -nm_sources = $(nm_device_headers) $(nm_dhcp_client_headers) \ - devices/nm-device.c devices/nm-device.h \ - devices/nm-device-ethernet-utils.c \ +libNetworkManager_la_SOURCES = $(nm_device_headers) \ + $(nm_dhcp_client_headers) devices/nm-device.c \ + devices/nm-device.h devices/nm-lldp-listener.c \ + devices/nm-lldp-listener.h devices/nm-device-ethernet-utils.c \ devices/nm-device-ethernet-utils.h devices/nm-device-factory.c \ devices/nm-device-factory.h devices/nm-device-generic.c \ devices/nm-device-generic.h devices/nm-device-logging.h \ @@ -978,10 +1030,9 @@ nm_sources = $(nm_device_headers) $(nm_dhcp_client_headers) \ settings/nm-inotify-helper.c settings/nm-inotify-helper.h \ settings/nm-secret-agent.c settings/nm-secret-agent.h \ settings/nm-settings-connection.c \ - settings/nm-settings-connection.h settings/nm-settings.c \ - settings/nm-settings.h settings/nm-system-config-interface.c \ - settings/nm-system-config-interface.h \ - settings/plugins/keyfile/common.h \ + settings/nm-settings-connection.h \ + settings/nm-settings-plugin.c settings/nm-settings-plugin.h \ + settings/nm-settings.c settings/nm-settings.h \ settings/plugins/keyfile/nm-keyfile-connection.c \ settings/plugins/keyfile/nm-keyfile-connection.h \ settings/plugins/keyfile/plugin.c \ @@ -1003,70 +1054,43 @@ nm_sources = $(nm_device_headers) $(nm_dhcp_client_headers) \ supplicant-manager/nm-supplicant-types.h \ vpn-manager/nm-vpn-connection.c \ vpn-manager/nm-vpn-connection.h vpn-manager/nm-vpn-manager.c \ - vpn-manager/nm-vpn-manager.h vpn-manager/nm-vpn-service.c \ - vpn-manager/nm-vpn-service.h nm-activation-request.c \ + vpn-manager/nm-vpn-manager.h nm-activation-request.c \ nm-activation-request.h nm-active-connection.c \ - nm-active-connection.h nm-config.c nm-config.h \ + nm-active-connection.h nm-audit-manager.c nm-audit-manager.h \ + nm-bus-manager.c nm-bus-manager.h nm-config.c nm-config.h \ nm-config-data.c nm-config-data.h nm-connection-provider.c \ nm-connection-provider.h nm-connectivity.c nm-connectivity.h \ - nm-dbus-manager.c nm-dbus-manager.h nm-dcb.c nm-dcb.h \ - nm-route-manager.c nm-route-manager.h \ + nm-dcb.c nm-dcb.h nm-route-manager.c nm-route-manager.h \ nm-default-route-manager.c nm-default-route-manager.h \ nm-dhcp4-config.c nm-dhcp4-config.h nm-dhcp6-config.c \ nm-dhcp6-config.h nm-dispatcher.c nm-dispatcher.h \ - nm-enum-types.c nm-enum-types.h nm-firewall-manager.c \ + nm-enum-types.c nm-enum-types.h nm-exported-object.c \ + nm-exported-object.h nm-firewall-manager.c \ nm-firewall-manager.h nm-ip4-config.c nm-ip4-config.h \ nm-ip6-config.c nm-ip6-config.h nm-logging.c nm-logging.h \ nm-auth-manager.c nm-auth-manager.h nm-auth-subject.c \ nm-auth-subject.h nm-auth-utils.c nm-auth-utils.h nm-manager.c \ nm-manager.h nm-multi-index.c nm-multi-index.h nm-policy.c \ - nm-policy.h nm-properties-changed-signal.c \ - nm-properties-changed-signal.h nm-rfkill-manager.c \ - nm-rfkill-manager.h nm-session-monitor.h nm-session-utils.c \ - nm-session-utils.h nm-sleep-monitor.h nm-types.h \ - NetworkManagerUtils.c NetworkManagerUtils.h $(am__append_6) \ - $(am__append_7) $(am__append_8) $(am__append_9) \ - $(am__append_10) $(am__append_11) + nm-policy.h nm-rfkill-manager.c nm-rfkill-manager.h \ + nm-session-monitor.h nm-session-monitor.c nm-sleep-monitor.h \ + nm-types.h NetworkManagerUtils.c NetworkManagerUtils.h \ + $(am__append_5) $(am__append_6) $(am__append_7) GLIB_GENERATED = nm-enum-types.h nm-enum-types.c GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM --fhead '\#include \n' GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM -nm_enum_types_sources = $(nm_sources) $(am__append_12) -BUILT_SOURCES = $(GLIB_GENERATED) $(glue_sources) -glue_sources = \ - nm-access-point-glue.h \ - nm-active-connection-glue.h \ - nm-agent-manager-glue.h \ - nm-device-bond-glue.h \ - nm-device-bridge-glue.h \ - nm-device-ethernet-glue.h \ - nm-device-generic-glue.h \ - nm-device-glue.h \ - nm-device-gre-glue.h \ - nm-device-infiniband-glue.h \ - nm-device-macvlan-glue.h \ - nm-device-tun-glue.h \ - nm-device-veth-glue.h \ - nm-device-vlan-glue.h \ - nm-device-vxlan-glue.h \ - nm-dhcp4-config-glue.h \ - nm-dhcp6-config-glue.h \ - nm-ip4-config-glue.h \ - nm-ip6-config-glue.h \ - nm-manager-glue.h \ - nm-ppp-manager-glue.h \ - nm-settings-connection-glue.h \ - nm-settings-glue.h \ - nm-vpn-connection-glue.h - -libNetworkManager_la_SOURCES = \ - $(nm_sources) \ - $(glue_sources) +nm_enum_types_sources = $(filter-out \ + %/nm-device-private.h \ + %/nm-rdisc-private.h \ + %/wifi-utils-private.h \ + , $(libNetworkManager_la_SOURCES)) +BUILT_SOURCES = $(GLIB_GENERATED) libNetworkManager_la_LIBADD = \ - $(top_builddir)/libnm-core/libnm-core.la libsystemd-dhcp.la \ - $(DBUS_LIBS) $(GLIB_LIBS) $(GUDEV_LIBS) $(LIBNL_LIBS) \ - $(SYSTEMD_LOGIN_LIBS) $(LIBNDP_LIBS) $(LIBDL) $(LIBM) \ - $(am__append_15) + $(top_builddir)/libnm-core/libnm-core.la \ + $(top_builddir)/introspection/libnmdbus.la libsystemd-nm.la \ + $(GLIB_LIBS) $(GUDEV_LIBS) $(LIBNL_LIBS) $(SYSTEMD_LOGIN_LIBS) \ + $(SYSTEMD_JOURNAL_LIBS) $(LIBNDP_LIBS) $(LIBDL) $(LIBM) \ + $(SELINUX_LIBS) $(LIBAUDIT_LIBS) $(am__append_8) NetworkManager_LDFLAGS = -rdynamic ###################### @@ -1083,15 +1107,16 @@ libnm_iface_helper_la_SOURCES = dhcp-manager/nm-dhcp-client.c \ platform/wifi/wifi-utils.h rdisc/nm-fake-rdisc.c \ rdisc/nm-fake-rdisc.h rdisc/nm-lndp-rdisc.c \ rdisc/nm-lndp-rdisc.h rdisc/nm-rdisc.c rdisc/nm-rdisc.h \ - nm-route-manager.c nm-route-manager.h nm-ip4-config.c \ - nm-ip4-config.h nm-ip6-config.c nm-ip6-config.h \ - nm-enum-types.c nm-enum-types.h nm-logging.c nm-logging.h \ - nm-multi-index.c nm-multi-index.h NetworkManagerUtils.c \ - NetworkManagerUtils.h $(am__append_16) + nm-route-manager.c nm-route-manager.h nm-exported-object.c \ + nm-exported-object.h nm-ip4-config.c nm-ip4-config.h \ + nm-ip6-config.c nm-ip6-config.h nm-enum-types.c \ + nm-enum-types.h nm-logging.c nm-logging.h nm-multi-index.c \ + nm-multi-index.h NetworkManagerUtils.c NetworkManagerUtils.h \ + $(am__append_9) libnm_iface_helper_la_LIBADD = \ $(top_builddir)/libnm-core/libnm-core.la \ - libsystemd-dhcp.la \ - $(DBUS_LIBS) \ + $(top_builddir)/introspection/libnmdbus.la \ + libsystemd-nm.la \ $(GLIB_LIBS) \ $(GUDEV_LIBS) \ $(LIBNL_LIBS) \ @@ -1108,11 +1133,11 @@ nm_iface_helper_SOURCES = \ nm_iface_helper_LDADD = \ $(top_builddir)/libnm-core/libnm-core.la \ - libsystemd-dhcp.la \ + libsystemd-nm.la \ libnm-iface-helper.la \ - $(DBUS_LIBS) \ $(GLIB_LIBS) \ $(GUDEV_LIBS) \ + $(SYSTEMD_JOURNAL_LIBS) \ $(LIBNL_LIBS) \ $(LIBNDP_LIBS) \ $(LIBM) @@ -1126,13 +1151,10 @@ EXTRA_DIST = \ $(dbusservice_DATA) \ $(NetworkManager_DATA) -rundir = $(localstatedir)/run/NetworkManager +rundir = $(runstatedir)/NetworkManager statedir = $(localstatedir)/lib/NetworkManager CLEANFILES = \ - $(BUILT_SOURCES) \ - settings/*-glue.h \ - devices/*-glue.h \ - devices/*/*-glue.h + $(BUILT_SOURCES) all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-recursive @@ -1186,8 +1208,8 @@ libNetworkManager.la: $(libNetworkManager_la_OBJECTS) $(libNetworkManager_la_DEP libnm-iface-helper.la: $(libnm_iface_helper_la_OBJECTS) $(libnm_iface_helper_la_DEPENDENCIES) $(EXTRA_libnm_iface_helper_la_DEPENDENCIES) $(AM_V_CCLD)$(LINK) $(libnm_iface_helper_la_OBJECTS) $(libnm_iface_helper_la_LIBADD) $(LIBS) -libsystemd-dhcp.la: $(libsystemd_dhcp_la_OBJECTS) $(libsystemd_dhcp_la_DEPENDENCIES) $(EXTRA_libsystemd_dhcp_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libsystemd_dhcp_la_OBJECTS) $(libsystemd_dhcp_la_LIBADD) $(LIBS) +libsystemd-nm.la: $(libsystemd_nm_la_OBJECTS) $(libsystemd_nm_la_DEPENDENCIES) $(EXTRA_libsystemd_nm_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libsystemd_nm_la_OBJECTS) $(libsystemd_nm_la_LIBADD) $(LIBS) install-libexecPROGRAMS: $(libexec_PROGRAMS) @$(NORMAL_INSTALL) @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ @@ -1302,37 +1324,64 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NetworkManagerUtils.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-dhcp-network.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-dhcp-option.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-dhcp-packet.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-dhcp6-network.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-dhcp6-option.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-fileio.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-in-addr-util.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-network-internal.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-nm-sd-adapt.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-sd-dhcp-client.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-sd-dhcp-lease.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-sd-dhcp6-client.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-sd-dhcp6-lease.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-siphash24.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-strv.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-time-util.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-utf8.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_dhcp_la-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-alloc-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-arp-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-dhcp-identifier.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-dhcp-network.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-dhcp-option.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-dhcp-packet.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-dhcp6-network.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-dhcp6-option.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-dns-domain.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-escape.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-fd-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-fileio.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-fs-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-hashmap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-hexdecoct.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-hostname-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-in-addr-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-io-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-lldp-internal.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-lldp-network.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-lldp-port.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-lldp-tlv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-mempool.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-network-internal.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-nm-sd-adapt.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-parse-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-path-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-prioq.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-random-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-sd-dhcp-client.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-sd-dhcp-lease.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-sd-dhcp6-client.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-sd-dhcp6-lease.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-sd-id128.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-sd-ipv4acd.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-sd-ipv4ll.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-sd-lldp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-siphash24.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-string-table.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-string-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-strv.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-time-util.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-utf8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsystemd_nm_la-util.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main-utils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-activation-request.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-active-connection.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-agent-manager.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-audit-manager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-auth-manager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-auth-subject.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-auth-utils.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-bus-manager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-config-data.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-config.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-connection-provider.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-connectivity.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-dbus-manager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-dcb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-default-route-manager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-device-bond.Po@am__quote@ @@ -1341,8 +1390,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-device-ethernet.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-device-factory.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-device-generic.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-device-gre.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-device-infiniband.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-device-ip-tunnel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-device-macvlan.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-device-tun.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-device-veth.Po@am__quote@ @@ -1368,6 +1417,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-dnsmasq-manager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-dnsmasq-utils.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-enum-types.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-exported-object.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-fake-platform.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-fake-rdisc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-firewall-manager.Plo@am__quote@ @@ -1377,6 +1427,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-ip6-config.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-keyfile-connection.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-linux-platform.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-lldp-listener.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-lndp-rdisc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-logging.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-manager.Plo@am__quote@ @@ -1385,16 +1436,13 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-platform.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-policy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-ppp-manager.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-properties-changed-signal.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-rdisc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-rfkill-manager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-route-manager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-secret-agent.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-session-monitor-ck.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-session-monitor-null.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-session-monitor-systemd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-session-utils.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-session-monitor.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-settings-connection.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-settings-plugin.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-settings.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-sleep-monitor-systemd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-sleep-monitor-upower.Plo@am__quote@ @@ -1402,10 +1450,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-supplicant-interface.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-supplicant-manager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-supplicant-settings-verify.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-system-config-interface.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-vpn-connection.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-vpn-manager.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-vpn-service.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nmp-object.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reader.Plo@am__quote@ @@ -1443,6 +1489,13 @@ nm-device.lo: devices/nm-device.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-device.lo `test -f 'devices/nm-device.c' || echo '$(srcdir)/'`devices/nm-device.c +nm-lldp-listener.lo: devices/nm-lldp-listener.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-lldp-listener.lo -MD -MP -MF $(DEPDIR)/nm-lldp-listener.Tpo -c -o nm-lldp-listener.lo `test -f 'devices/nm-lldp-listener.c' || echo '$(srcdir)/'`devices/nm-lldp-listener.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-lldp-listener.Tpo $(DEPDIR)/nm-lldp-listener.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='devices/nm-lldp-listener.c' object='nm-lldp-listener.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-lldp-listener.lo `test -f 'devices/nm-lldp-listener.c' || echo '$(srcdir)/'`devices/nm-lldp-listener.c + nm-device-ethernet-utils.lo: devices/nm-device-ethernet-utils.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-device-ethernet-utils.lo -MD -MP -MF $(DEPDIR)/nm-device-ethernet-utils.Tpo -c -o nm-device-ethernet-utils.lo `test -f 'devices/nm-device-ethernet-utils.c' || echo '$(srcdir)/'`devices/nm-device-ethernet-utils.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-device-ethernet-utils.Tpo $(DEPDIR)/nm-device-ethernet-utils.Plo @@ -1646,6 +1699,13 @@ nm-settings-connection.lo: settings/nm-settings-connection.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-settings-connection.lo `test -f 'settings/nm-settings-connection.c' || echo '$(srcdir)/'`settings/nm-settings-connection.c +nm-settings-plugin.lo: settings/nm-settings-plugin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-settings-plugin.lo -MD -MP -MF $(DEPDIR)/nm-settings-plugin.Tpo -c -o nm-settings-plugin.lo `test -f 'settings/nm-settings-plugin.c' || echo '$(srcdir)/'`settings/nm-settings-plugin.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-settings-plugin.Tpo $(DEPDIR)/nm-settings-plugin.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='settings/nm-settings-plugin.c' object='nm-settings-plugin.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-settings-plugin.lo `test -f 'settings/nm-settings-plugin.c' || echo '$(srcdir)/'`settings/nm-settings-plugin.c + nm-settings.lo: settings/nm-settings.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-settings.lo -MD -MP -MF $(DEPDIR)/nm-settings.Tpo -c -o nm-settings.lo `test -f 'settings/nm-settings.c' || echo '$(srcdir)/'`settings/nm-settings.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-settings.Tpo $(DEPDIR)/nm-settings.Plo @@ -1653,13 +1713,6 @@ nm-settings.lo: settings/nm-settings.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-settings.lo `test -f 'settings/nm-settings.c' || echo '$(srcdir)/'`settings/nm-settings.c -nm-system-config-interface.lo: settings/nm-system-config-interface.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-system-config-interface.lo -MD -MP -MF $(DEPDIR)/nm-system-config-interface.Tpo -c -o nm-system-config-interface.lo `test -f 'settings/nm-system-config-interface.c' || echo '$(srcdir)/'`settings/nm-system-config-interface.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-system-config-interface.Tpo $(DEPDIR)/nm-system-config-interface.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='settings/nm-system-config-interface.c' object='nm-system-config-interface.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-system-config-interface.lo `test -f 'settings/nm-system-config-interface.c' || echo '$(srcdir)/'`settings/nm-system-config-interface.c - nm-keyfile-connection.lo: settings/plugins/keyfile/nm-keyfile-connection.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-keyfile-connection.lo -MD -MP -MF $(DEPDIR)/nm-keyfile-connection.Tpo -c -o nm-keyfile-connection.lo `test -f 'settings/plugins/keyfile/nm-keyfile-connection.c' || echo '$(srcdir)/'`settings/plugins/keyfile/nm-keyfile-connection.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-keyfile-connection.Tpo $(DEPDIR)/nm-keyfile-connection.Plo @@ -1737,13 +1790,6 @@ nm-vpn-manager.lo: vpn-manager/nm-vpn-manager.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-vpn-manager.lo `test -f 'vpn-manager/nm-vpn-manager.c' || echo '$(srcdir)/'`vpn-manager/nm-vpn-manager.c -nm-vpn-service.lo: vpn-manager/nm-vpn-service.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-vpn-service.lo -MD -MP -MF $(DEPDIR)/nm-vpn-service.Tpo -c -o nm-vpn-service.lo `test -f 'vpn-manager/nm-vpn-service.c' || echo '$(srcdir)/'`vpn-manager/nm-vpn-service.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-vpn-service.Tpo $(DEPDIR)/nm-vpn-service.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vpn-manager/nm-vpn-service.c' object='nm-vpn-service.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nm-vpn-service.lo `test -f 'vpn-manager/nm-vpn-service.c' || echo '$(srcdir)/'`vpn-manager/nm-vpn-service.c - wifi-utils-wext.lo: platform/wifi/wifi-utils-wext.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT wifi-utils-wext.lo -MD -MP -MF $(DEPDIR)/wifi-utils-wext.Tpo -c -o wifi-utils-wext.lo `test -f 'platform/wifi/wifi-utils-wext.c' || echo '$(srcdir)/'`platform/wifi/wifi-utils-wext.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wifi-utils-wext.Tpo $(DEPDIR)/wifi-utils-wext.Plo @@ -1751,131 +1797,313 @@ wifi-utils-wext.lo: platform/wifi/wifi-utils-wext.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o wifi-utils-wext.lo `test -f 'platform/wifi/wifi-utils-wext.c' || echo '$(srcdir)/'`platform/wifi/wifi-utils-wext.c -libsystemd_dhcp_la-dhcp-network.lo: dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-dhcp-network.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-dhcp-network.Tpo -c -o libsystemd_dhcp_la-dhcp-network.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-dhcp-network.Tpo $(DEPDIR)/libsystemd_dhcp_la-dhcp-network.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c' object='libsystemd_dhcp_la-dhcp-network.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-nm-sd-adapt.lo: systemd/nm-sd-adapt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-nm-sd-adapt.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-nm-sd-adapt.Tpo -c -o libsystemd_nm_la-nm-sd-adapt.lo `test -f 'systemd/nm-sd-adapt.c' || echo '$(srcdir)/'`systemd/nm-sd-adapt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-nm-sd-adapt.Tpo $(DEPDIR)/libsystemd_nm_la-nm-sd-adapt.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/nm-sd-adapt.c' object='libsystemd_nm_la-nm-sd-adapt.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-dhcp-network.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-nm-sd-adapt.lo `test -f 'systemd/nm-sd-adapt.c' || echo '$(srcdir)/'`systemd/nm-sd-adapt.c -libsystemd_dhcp_la-dhcp-packet.lo: dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-dhcp-packet.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-dhcp-packet.Tpo -c -o libsystemd_dhcp_la-dhcp-packet.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-dhcp-packet.Tpo $(DEPDIR)/libsystemd_dhcp_la-dhcp-packet.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c' object='libsystemd_dhcp_la-dhcp-packet.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-alloc-util.lo: systemd/src/basic/alloc-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-alloc-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-alloc-util.Tpo -c -o libsystemd_nm_la-alloc-util.lo `test -f 'systemd/src/basic/alloc-util.c' || echo '$(srcdir)/'`systemd/src/basic/alloc-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-alloc-util.Tpo $(DEPDIR)/libsystemd_nm_la-alloc-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/alloc-util.c' object='libsystemd_nm_la-alloc-util.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-dhcp-packet.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-alloc-util.lo `test -f 'systemd/src/basic/alloc-util.c' || echo '$(srcdir)/'`systemd/src/basic/alloc-util.c -libsystemd_dhcp_la-dhcp6-network.lo: dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-network.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-dhcp6-network.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-dhcp6-network.Tpo -c -o libsystemd_dhcp_la-dhcp6-network.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-network.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-network.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-dhcp6-network.Tpo $(DEPDIR)/libsystemd_dhcp_la-dhcp6-network.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-network.c' object='libsystemd_dhcp_la-dhcp6-network.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-escape.lo: systemd/src/basic/escape.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-escape.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-escape.Tpo -c -o libsystemd_nm_la-escape.lo `test -f 'systemd/src/basic/escape.c' || echo '$(srcdir)/'`systemd/src/basic/escape.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-escape.Tpo $(DEPDIR)/libsystemd_nm_la-escape.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/escape.c' object='libsystemd_nm_la-escape.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-dhcp6-network.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-network.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-network.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-escape.lo `test -f 'systemd/src/basic/escape.c' || echo '$(srcdir)/'`systemd/src/basic/escape.c -libsystemd_dhcp_la-dhcp6-option.lo: dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-dhcp6-option.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-dhcp6-option.Tpo -c -o libsystemd_dhcp_la-dhcp6-option.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-dhcp6-option.Tpo $(DEPDIR)/libsystemd_dhcp_la-dhcp6-option.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c' object='libsystemd_dhcp_la-dhcp6-option.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-fd-util.lo: systemd/src/basic/fd-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-fd-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-fd-util.Tpo -c -o libsystemd_nm_la-fd-util.lo `test -f 'systemd/src/basic/fd-util.c' || echo '$(srcdir)/'`systemd/src/basic/fd-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-fd-util.Tpo $(DEPDIR)/libsystemd_nm_la-fd-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/fd-util.c' object='libsystemd_nm_la-fd-util.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-dhcp6-option.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-fd-util.lo `test -f 'systemd/src/basic/fd-util.c' || echo '$(srcdir)/'`systemd/src/basic/fd-util.c -libsystemd_dhcp_la-network-internal.lo: dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-network-internal.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-network-internal.Tpo -c -o libsystemd_dhcp_la-network-internal.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-network-internal.Tpo $(DEPDIR)/libsystemd_dhcp_la-network-internal.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c' object='libsystemd_dhcp_la-network-internal.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-fileio.lo: systemd/src/basic/fileio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-fileio.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-fileio.Tpo -c -o libsystemd_nm_la-fileio.lo `test -f 'systemd/src/basic/fileio.c' || echo '$(srcdir)/'`systemd/src/basic/fileio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-fileio.Tpo $(DEPDIR)/libsystemd_nm_la-fileio.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/fileio.c' object='libsystemd_nm_la-fileio.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-network-internal.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-fileio.lo `test -f 'systemd/src/basic/fileio.c' || echo '$(srcdir)/'`systemd/src/basic/fileio.c -libsystemd_dhcp_la-sd-dhcp-lease.lo: dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-sd-dhcp-lease.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-sd-dhcp-lease.Tpo -c -o libsystemd_dhcp_la-sd-dhcp-lease.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-sd-dhcp-lease.Tpo $(DEPDIR)/libsystemd_dhcp_la-sd-dhcp-lease.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c' object='libsystemd_dhcp_la-sd-dhcp-lease.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-fs-util.lo: systemd/src/basic/fs-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-fs-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-fs-util.Tpo -c -o libsystemd_nm_la-fs-util.lo `test -f 'systemd/src/basic/fs-util.c' || echo '$(srcdir)/'`systemd/src/basic/fs-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-fs-util.Tpo $(DEPDIR)/libsystemd_nm_la-fs-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/fs-util.c' object='libsystemd_nm_la-fs-util.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-sd-dhcp-lease.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-fs-util.lo `test -f 'systemd/src/basic/fs-util.c' || echo '$(srcdir)/'`systemd/src/basic/fs-util.c -libsystemd_dhcp_la-sd-dhcp-client.lo: dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-sd-dhcp-client.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-sd-dhcp-client.Tpo -c -o libsystemd_dhcp_la-sd-dhcp-client.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-sd-dhcp-client.Tpo $(DEPDIR)/libsystemd_dhcp_la-sd-dhcp-client.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c' object='libsystemd_dhcp_la-sd-dhcp-client.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-hashmap.lo: systemd/src/basic/hashmap.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-hashmap.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-hashmap.Tpo -c -o libsystemd_nm_la-hashmap.lo `test -f 'systemd/src/basic/hashmap.c' || echo '$(srcdir)/'`systemd/src/basic/hashmap.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-hashmap.Tpo $(DEPDIR)/libsystemd_nm_la-hashmap.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/hashmap.c' object='libsystemd_nm_la-hashmap.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-sd-dhcp-client.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-hashmap.lo `test -f 'systemd/src/basic/hashmap.c' || echo '$(srcdir)/'`systemd/src/basic/hashmap.c -libsystemd_dhcp_la-dhcp-option.lo: dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-option.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-dhcp-option.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-dhcp-option.Tpo -c -o libsystemd_dhcp_la-dhcp-option.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-option.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-option.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-dhcp-option.Tpo $(DEPDIR)/libsystemd_dhcp_la-dhcp-option.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-option.c' object='libsystemd_dhcp_la-dhcp-option.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-hexdecoct.lo: systemd/src/basic/hexdecoct.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-hexdecoct.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-hexdecoct.Tpo -c -o libsystemd_nm_la-hexdecoct.lo `test -f 'systemd/src/basic/hexdecoct.c' || echo '$(srcdir)/'`systemd/src/basic/hexdecoct.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-hexdecoct.Tpo $(DEPDIR)/libsystemd_nm_la-hexdecoct.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/hexdecoct.c' object='libsystemd_nm_la-hexdecoct.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-dhcp-option.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-option.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-option.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-hexdecoct.lo `test -f 'systemd/src/basic/hexdecoct.c' || echo '$(srcdir)/'`systemd/src/basic/hexdecoct.c -libsystemd_dhcp_la-sd-dhcp6-lease.lo: dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-sd-dhcp6-lease.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-sd-dhcp6-lease.Tpo -c -o libsystemd_dhcp_la-sd-dhcp6-lease.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-sd-dhcp6-lease.Tpo $(DEPDIR)/libsystemd_dhcp_la-sd-dhcp6-lease.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c' object='libsystemd_dhcp_la-sd-dhcp6-lease.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-hostname-util.lo: systemd/src/basic/hostname-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-hostname-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-hostname-util.Tpo -c -o libsystemd_nm_la-hostname-util.lo `test -f 'systemd/src/basic/hostname-util.c' || echo '$(srcdir)/'`systemd/src/basic/hostname-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-hostname-util.Tpo $(DEPDIR)/libsystemd_nm_la-hostname-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/hostname-util.c' object='libsystemd_nm_la-hostname-util.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-sd-dhcp6-lease.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-hostname-util.lo `test -f 'systemd/src/basic/hostname-util.c' || echo '$(srcdir)/'`systemd/src/basic/hostname-util.c -libsystemd_dhcp_la-sd-dhcp6-client.lo: dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-sd-dhcp6-client.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-sd-dhcp6-client.Tpo -c -o libsystemd_dhcp_la-sd-dhcp6-client.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-sd-dhcp6-client.Tpo $(DEPDIR)/libsystemd_dhcp_la-sd-dhcp6-client.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c' object='libsystemd_dhcp_la-sd-dhcp6-client.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-in-addr-util.lo: systemd/src/basic/in-addr-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-in-addr-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-in-addr-util.Tpo -c -o libsystemd_nm_la-in-addr-util.lo `test -f 'systemd/src/basic/in-addr-util.c' || echo '$(srcdir)/'`systemd/src/basic/in-addr-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-in-addr-util.Tpo $(DEPDIR)/libsystemd_nm_la-in-addr-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/in-addr-util.c' object='libsystemd_nm_la-in-addr-util.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-sd-dhcp6-client.lo `test -f 'dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-in-addr-util.lo `test -f 'systemd/src/basic/in-addr-util.c' || echo '$(srcdir)/'`systemd/src/basic/in-addr-util.c -libsystemd_dhcp_la-time-util.lo: dhcp-manager/systemd-dhcp/src/shared/time-util.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-time-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-time-util.Tpo -c -o libsystemd_dhcp_la-time-util.lo `test -f 'dhcp-manager/systemd-dhcp/src/shared/time-util.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/shared/time-util.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-time-util.Tpo $(DEPDIR)/libsystemd_dhcp_la-time-util.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/shared/time-util.c' object='libsystemd_dhcp_la-time-util.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-io-util.lo: systemd/src/basic/io-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-io-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-io-util.Tpo -c -o libsystemd_nm_la-io-util.lo `test -f 'systemd/src/basic/io-util.c' || echo '$(srcdir)/'`systemd/src/basic/io-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-io-util.Tpo $(DEPDIR)/libsystemd_nm_la-io-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/io-util.c' object='libsystemd_nm_la-io-util.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-time-util.lo `test -f 'dhcp-manager/systemd-dhcp/src/shared/time-util.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/shared/time-util.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-io-util.lo `test -f 'systemd/src/basic/io-util.c' || echo '$(srcdir)/'`systemd/src/basic/io-util.c -libsystemd_dhcp_la-util.lo: dhcp-manager/systemd-dhcp/src/shared/util.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-util.Tpo -c -o libsystemd_dhcp_la-util.lo `test -f 'dhcp-manager/systemd-dhcp/src/shared/util.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/shared/util.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-util.Tpo $(DEPDIR)/libsystemd_dhcp_la-util.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/shared/util.c' object='libsystemd_dhcp_la-util.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-mempool.lo: systemd/src/basic/mempool.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-mempool.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-mempool.Tpo -c -o libsystemd_nm_la-mempool.lo `test -f 'systemd/src/basic/mempool.c' || echo '$(srcdir)/'`systemd/src/basic/mempool.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-mempool.Tpo $(DEPDIR)/libsystemd_nm_la-mempool.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/mempool.c' object='libsystemd_nm_la-mempool.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-util.lo `test -f 'dhcp-manager/systemd-dhcp/src/shared/util.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/shared/util.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-mempool.lo `test -f 'systemd/src/basic/mempool.c' || echo '$(srcdir)/'`systemd/src/basic/mempool.c -libsystemd_dhcp_la-in-addr-util.lo: dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-in-addr-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-in-addr-util.Tpo -c -o libsystemd_dhcp_la-in-addr-util.lo `test -f 'dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-in-addr-util.Tpo $(DEPDIR)/libsystemd_dhcp_la-in-addr-util.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c' object='libsystemd_dhcp_la-in-addr-util.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-parse-util.lo: systemd/src/basic/parse-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-parse-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-parse-util.Tpo -c -o libsystemd_nm_la-parse-util.lo `test -f 'systemd/src/basic/parse-util.c' || echo '$(srcdir)/'`systemd/src/basic/parse-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-parse-util.Tpo $(DEPDIR)/libsystemd_nm_la-parse-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/parse-util.c' object='libsystemd_nm_la-parse-util.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-in-addr-util.lo `test -f 'dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-parse-util.lo `test -f 'systemd/src/basic/parse-util.c' || echo '$(srcdir)/'`systemd/src/basic/parse-util.c -libsystemd_dhcp_la-siphash24.lo: dhcp-manager/systemd-dhcp/src/shared/siphash24.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-siphash24.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-siphash24.Tpo -c -o libsystemd_dhcp_la-siphash24.lo `test -f 'dhcp-manager/systemd-dhcp/src/shared/siphash24.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/shared/siphash24.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-siphash24.Tpo $(DEPDIR)/libsystemd_dhcp_la-siphash24.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/shared/siphash24.c' object='libsystemd_dhcp_la-siphash24.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-path-util.lo: systemd/src/basic/path-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-path-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-path-util.Tpo -c -o libsystemd_nm_la-path-util.lo `test -f 'systemd/src/basic/path-util.c' || echo '$(srcdir)/'`systemd/src/basic/path-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-path-util.Tpo $(DEPDIR)/libsystemd_nm_la-path-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/path-util.c' object='libsystemd_nm_la-path-util.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-siphash24.lo `test -f 'dhcp-manager/systemd-dhcp/src/shared/siphash24.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/shared/siphash24.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-path-util.lo `test -f 'systemd/src/basic/path-util.c' || echo '$(srcdir)/'`systemd/src/basic/path-util.c -libsystemd_dhcp_la-fileio.lo: dhcp-manager/systemd-dhcp/src/shared/fileio.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-fileio.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-fileio.Tpo -c -o libsystemd_dhcp_la-fileio.lo `test -f 'dhcp-manager/systemd-dhcp/src/shared/fileio.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/shared/fileio.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-fileio.Tpo $(DEPDIR)/libsystemd_dhcp_la-fileio.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/shared/fileio.c' object='libsystemd_dhcp_la-fileio.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-prioq.lo: systemd/src/basic/prioq.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-prioq.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-prioq.Tpo -c -o libsystemd_nm_la-prioq.lo `test -f 'systemd/src/basic/prioq.c' || echo '$(srcdir)/'`systemd/src/basic/prioq.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-prioq.Tpo $(DEPDIR)/libsystemd_nm_la-prioq.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/prioq.c' object='libsystemd_nm_la-prioq.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-fileio.lo `test -f 'dhcp-manager/systemd-dhcp/src/shared/fileio.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/shared/fileio.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-prioq.lo `test -f 'systemd/src/basic/prioq.c' || echo '$(srcdir)/'`systemd/src/basic/prioq.c -libsystemd_dhcp_la-strv.lo: dhcp-manager/systemd-dhcp/src/shared/strv.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-strv.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-strv.Tpo -c -o libsystemd_dhcp_la-strv.lo `test -f 'dhcp-manager/systemd-dhcp/src/shared/strv.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/shared/strv.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-strv.Tpo $(DEPDIR)/libsystemd_dhcp_la-strv.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/shared/strv.c' object='libsystemd_dhcp_la-strv.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-random-util.lo: systemd/src/basic/random-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-random-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-random-util.Tpo -c -o libsystemd_nm_la-random-util.lo `test -f 'systemd/src/basic/random-util.c' || echo '$(srcdir)/'`systemd/src/basic/random-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-random-util.Tpo $(DEPDIR)/libsystemd_nm_la-random-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/random-util.c' object='libsystemd_nm_la-random-util.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-strv.lo `test -f 'dhcp-manager/systemd-dhcp/src/shared/strv.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/shared/strv.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-random-util.lo `test -f 'systemd/src/basic/random-util.c' || echo '$(srcdir)/'`systemd/src/basic/random-util.c -libsystemd_dhcp_la-utf8.lo: dhcp-manager/systemd-dhcp/src/shared/utf8.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-utf8.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-utf8.Tpo -c -o libsystemd_dhcp_la-utf8.lo `test -f 'dhcp-manager/systemd-dhcp/src/shared/utf8.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/shared/utf8.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-utf8.Tpo $(DEPDIR)/libsystemd_dhcp_la-utf8.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/src/shared/utf8.c' object='libsystemd_dhcp_la-utf8.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-siphash24.lo: systemd/src/basic/siphash24.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-siphash24.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-siphash24.Tpo -c -o libsystemd_nm_la-siphash24.lo `test -f 'systemd/src/basic/siphash24.c' || echo '$(srcdir)/'`systemd/src/basic/siphash24.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-siphash24.Tpo $(DEPDIR)/libsystemd_nm_la-siphash24.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/siphash24.c' object='libsystemd_nm_la-siphash24.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-utf8.lo `test -f 'dhcp-manager/systemd-dhcp/src/shared/utf8.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/src/shared/utf8.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-siphash24.lo `test -f 'systemd/src/basic/siphash24.c' || echo '$(srcdir)/'`systemd/src/basic/siphash24.c -libsystemd_dhcp_la-nm-sd-adapt.lo: dhcp-manager/systemd-dhcp/nm-sd-adapt.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_dhcp_la-nm-sd-adapt.lo -MD -MP -MF $(DEPDIR)/libsystemd_dhcp_la-nm-sd-adapt.Tpo -c -o libsystemd_dhcp_la-nm-sd-adapt.lo `test -f 'dhcp-manager/systemd-dhcp/nm-sd-adapt.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/nm-sd-adapt.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_dhcp_la-nm-sd-adapt.Tpo $(DEPDIR)/libsystemd_dhcp_la-nm-sd-adapt.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dhcp-manager/systemd-dhcp/nm-sd-adapt.c' object='libsystemd_dhcp_la-nm-sd-adapt.lo' libtool=yes @AMDEPBACKSLASH@ +libsystemd_nm_la-string-table.lo: systemd/src/basic/string-table.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-string-table.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-string-table.Tpo -c -o libsystemd_nm_la-string-table.lo `test -f 'systemd/src/basic/string-table.c' || echo '$(srcdir)/'`systemd/src/basic/string-table.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-string-table.Tpo $(DEPDIR)/libsystemd_nm_la-string-table.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/string-table.c' object='libsystemd_nm_la-string-table.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_dhcp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_dhcp_la-nm-sd-adapt.lo `test -f 'dhcp-manager/systemd-dhcp/nm-sd-adapt.c' || echo '$(srcdir)/'`dhcp-manager/systemd-dhcp/nm-sd-adapt.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-string-table.lo `test -f 'systemd/src/basic/string-table.c' || echo '$(srcdir)/'`systemd/src/basic/string-table.c + +libsystemd_nm_la-string-util.lo: systemd/src/basic/string-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-string-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-string-util.Tpo -c -o libsystemd_nm_la-string-util.lo `test -f 'systemd/src/basic/string-util.c' || echo '$(srcdir)/'`systemd/src/basic/string-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-string-util.Tpo $(DEPDIR)/libsystemd_nm_la-string-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/string-util.c' object='libsystemd_nm_la-string-util.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-string-util.lo `test -f 'systemd/src/basic/string-util.c' || echo '$(srcdir)/'`systemd/src/basic/string-util.c + +libsystemd_nm_la-strv.lo: systemd/src/basic/strv.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-strv.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-strv.Tpo -c -o libsystemd_nm_la-strv.lo `test -f 'systemd/src/basic/strv.c' || echo '$(srcdir)/'`systemd/src/basic/strv.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-strv.Tpo $(DEPDIR)/libsystemd_nm_la-strv.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/strv.c' object='libsystemd_nm_la-strv.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-strv.lo `test -f 'systemd/src/basic/strv.c' || echo '$(srcdir)/'`systemd/src/basic/strv.c + +libsystemd_nm_la-time-util.lo: systemd/src/basic/time-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-time-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-time-util.Tpo -c -o libsystemd_nm_la-time-util.lo `test -f 'systemd/src/basic/time-util.c' || echo '$(srcdir)/'`systemd/src/basic/time-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-time-util.Tpo $(DEPDIR)/libsystemd_nm_la-time-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/time-util.c' object='libsystemd_nm_la-time-util.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-time-util.lo `test -f 'systemd/src/basic/time-util.c' || echo '$(srcdir)/'`systemd/src/basic/time-util.c + +libsystemd_nm_la-utf8.lo: systemd/src/basic/utf8.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-utf8.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-utf8.Tpo -c -o libsystemd_nm_la-utf8.lo `test -f 'systemd/src/basic/utf8.c' || echo '$(srcdir)/'`systemd/src/basic/utf8.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-utf8.Tpo $(DEPDIR)/libsystemd_nm_la-utf8.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/utf8.c' object='libsystemd_nm_la-utf8.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-utf8.lo `test -f 'systemd/src/basic/utf8.c' || echo '$(srcdir)/'`systemd/src/basic/utf8.c + +libsystemd_nm_la-util.lo: systemd/src/basic/util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-util.Tpo -c -o libsystemd_nm_la-util.lo `test -f 'systemd/src/basic/util.c' || echo '$(srcdir)/'`systemd/src/basic/util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-util.Tpo $(DEPDIR)/libsystemd_nm_la-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/basic/util.c' object='libsystemd_nm_la-util.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-util.lo `test -f 'systemd/src/basic/util.c' || echo '$(srcdir)/'`systemd/src/basic/util.c + +libsystemd_nm_la-arp-util.lo: systemd/src/libsystemd-network/arp-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-arp-util.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-arp-util.Tpo -c -o libsystemd_nm_la-arp-util.lo `test -f 'systemd/src/libsystemd-network/arp-util.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/arp-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-arp-util.Tpo $(DEPDIR)/libsystemd_nm_la-arp-util.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/arp-util.c' object='libsystemd_nm_la-arp-util.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-arp-util.lo `test -f 'systemd/src/libsystemd-network/arp-util.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/arp-util.c + +libsystemd_nm_la-dhcp-identifier.lo: systemd/src/libsystemd-network/dhcp-identifier.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-dhcp-identifier.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-dhcp-identifier.Tpo -c -o libsystemd_nm_la-dhcp-identifier.lo `test -f 'systemd/src/libsystemd-network/dhcp-identifier.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/dhcp-identifier.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-dhcp-identifier.Tpo $(DEPDIR)/libsystemd_nm_la-dhcp-identifier.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/dhcp-identifier.c' object='libsystemd_nm_la-dhcp-identifier.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-dhcp-identifier.lo `test -f 'systemd/src/libsystemd-network/dhcp-identifier.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/dhcp-identifier.c + +libsystemd_nm_la-dhcp-network.lo: systemd/src/libsystemd-network/dhcp-network.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-dhcp-network.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-dhcp-network.Tpo -c -o libsystemd_nm_la-dhcp-network.lo `test -f 'systemd/src/libsystemd-network/dhcp-network.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/dhcp-network.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-dhcp-network.Tpo $(DEPDIR)/libsystemd_nm_la-dhcp-network.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/dhcp-network.c' object='libsystemd_nm_la-dhcp-network.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-dhcp-network.lo `test -f 'systemd/src/libsystemd-network/dhcp-network.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/dhcp-network.c + +libsystemd_nm_la-dhcp-option.lo: systemd/src/libsystemd-network/dhcp-option.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-dhcp-option.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-dhcp-option.Tpo -c -o libsystemd_nm_la-dhcp-option.lo `test -f 'systemd/src/libsystemd-network/dhcp-option.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/dhcp-option.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-dhcp-option.Tpo $(DEPDIR)/libsystemd_nm_la-dhcp-option.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/dhcp-option.c' object='libsystemd_nm_la-dhcp-option.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-dhcp-option.lo `test -f 'systemd/src/libsystemd-network/dhcp-option.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/dhcp-option.c + +libsystemd_nm_la-dhcp-packet.lo: systemd/src/libsystemd-network/dhcp-packet.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-dhcp-packet.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-dhcp-packet.Tpo -c -o libsystemd_nm_la-dhcp-packet.lo `test -f 'systemd/src/libsystemd-network/dhcp-packet.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/dhcp-packet.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-dhcp-packet.Tpo $(DEPDIR)/libsystemd_nm_la-dhcp-packet.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/dhcp-packet.c' object='libsystemd_nm_la-dhcp-packet.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-dhcp-packet.lo `test -f 'systemd/src/libsystemd-network/dhcp-packet.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/dhcp-packet.c + +libsystemd_nm_la-dhcp6-network.lo: systemd/src/libsystemd-network/dhcp6-network.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-dhcp6-network.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-dhcp6-network.Tpo -c -o libsystemd_nm_la-dhcp6-network.lo `test -f 'systemd/src/libsystemd-network/dhcp6-network.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/dhcp6-network.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-dhcp6-network.Tpo $(DEPDIR)/libsystemd_nm_la-dhcp6-network.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/dhcp6-network.c' object='libsystemd_nm_la-dhcp6-network.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-dhcp6-network.lo `test -f 'systemd/src/libsystemd-network/dhcp6-network.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/dhcp6-network.c + +libsystemd_nm_la-dhcp6-option.lo: systemd/src/libsystemd-network/dhcp6-option.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-dhcp6-option.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-dhcp6-option.Tpo -c -o libsystemd_nm_la-dhcp6-option.lo `test -f 'systemd/src/libsystemd-network/dhcp6-option.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/dhcp6-option.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-dhcp6-option.Tpo $(DEPDIR)/libsystemd_nm_la-dhcp6-option.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/dhcp6-option.c' object='libsystemd_nm_la-dhcp6-option.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-dhcp6-option.lo `test -f 'systemd/src/libsystemd-network/dhcp6-option.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/dhcp6-option.c + +libsystemd_nm_la-lldp-network.lo: systemd/src/libsystemd-network/lldp-network.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-lldp-network.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-lldp-network.Tpo -c -o libsystemd_nm_la-lldp-network.lo `test -f 'systemd/src/libsystemd-network/lldp-network.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/lldp-network.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-lldp-network.Tpo $(DEPDIR)/libsystemd_nm_la-lldp-network.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/lldp-network.c' object='libsystemd_nm_la-lldp-network.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-lldp-network.lo `test -f 'systemd/src/libsystemd-network/lldp-network.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/lldp-network.c + +libsystemd_nm_la-lldp-tlv.lo: systemd/src/libsystemd-network/lldp-tlv.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-lldp-tlv.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-lldp-tlv.Tpo -c -o libsystemd_nm_la-lldp-tlv.lo `test -f 'systemd/src/libsystemd-network/lldp-tlv.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/lldp-tlv.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-lldp-tlv.Tpo $(DEPDIR)/libsystemd_nm_la-lldp-tlv.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/lldp-tlv.c' object='libsystemd_nm_la-lldp-tlv.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-lldp-tlv.lo `test -f 'systemd/src/libsystemd-network/lldp-tlv.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/lldp-tlv.c + +libsystemd_nm_la-lldp-port.lo: systemd/src/libsystemd-network/lldp-port.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-lldp-port.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-lldp-port.Tpo -c -o libsystemd_nm_la-lldp-port.lo `test -f 'systemd/src/libsystemd-network/lldp-port.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/lldp-port.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-lldp-port.Tpo $(DEPDIR)/libsystemd_nm_la-lldp-port.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/lldp-port.c' object='libsystemd_nm_la-lldp-port.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-lldp-port.lo `test -f 'systemd/src/libsystemd-network/lldp-port.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/lldp-port.c + +libsystemd_nm_la-lldp-internal.lo: systemd/src/libsystemd-network/lldp-internal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-lldp-internal.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-lldp-internal.Tpo -c -o libsystemd_nm_la-lldp-internal.lo `test -f 'systemd/src/libsystemd-network/lldp-internal.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/lldp-internal.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-lldp-internal.Tpo $(DEPDIR)/libsystemd_nm_la-lldp-internal.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/lldp-internal.c' object='libsystemd_nm_la-lldp-internal.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-lldp-internal.lo `test -f 'systemd/src/libsystemd-network/lldp-internal.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/lldp-internal.c + +libsystemd_nm_la-network-internal.lo: systemd/src/libsystemd-network/network-internal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-network-internal.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-network-internal.Tpo -c -o libsystemd_nm_la-network-internal.lo `test -f 'systemd/src/libsystemd-network/network-internal.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/network-internal.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-network-internal.Tpo $(DEPDIR)/libsystemd_nm_la-network-internal.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/network-internal.c' object='libsystemd_nm_la-network-internal.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-network-internal.lo `test -f 'systemd/src/libsystemd-network/network-internal.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/network-internal.c + +libsystemd_nm_la-sd-dhcp-client.lo: systemd/src/libsystemd-network/sd-dhcp-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-sd-dhcp-client.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-sd-dhcp-client.Tpo -c -o libsystemd_nm_la-sd-dhcp-client.lo `test -f 'systemd/src/libsystemd-network/sd-dhcp-client.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/sd-dhcp-client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-sd-dhcp-client.Tpo $(DEPDIR)/libsystemd_nm_la-sd-dhcp-client.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/sd-dhcp-client.c' object='libsystemd_nm_la-sd-dhcp-client.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-sd-dhcp-client.lo `test -f 'systemd/src/libsystemd-network/sd-dhcp-client.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/sd-dhcp-client.c + +libsystemd_nm_la-sd-dhcp-lease.lo: systemd/src/libsystemd-network/sd-dhcp-lease.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-sd-dhcp-lease.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-sd-dhcp-lease.Tpo -c -o libsystemd_nm_la-sd-dhcp-lease.lo `test -f 'systemd/src/libsystemd-network/sd-dhcp-lease.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/sd-dhcp-lease.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-sd-dhcp-lease.Tpo $(DEPDIR)/libsystemd_nm_la-sd-dhcp-lease.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/sd-dhcp-lease.c' object='libsystemd_nm_la-sd-dhcp-lease.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-sd-dhcp-lease.lo `test -f 'systemd/src/libsystemd-network/sd-dhcp-lease.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/sd-dhcp-lease.c + +libsystemd_nm_la-sd-dhcp6-client.lo: systemd/src/libsystemd-network/sd-dhcp6-client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-sd-dhcp6-client.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-sd-dhcp6-client.Tpo -c -o libsystemd_nm_la-sd-dhcp6-client.lo `test -f 'systemd/src/libsystemd-network/sd-dhcp6-client.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/sd-dhcp6-client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-sd-dhcp6-client.Tpo $(DEPDIR)/libsystemd_nm_la-sd-dhcp6-client.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/sd-dhcp6-client.c' object='libsystemd_nm_la-sd-dhcp6-client.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-sd-dhcp6-client.lo `test -f 'systemd/src/libsystemd-network/sd-dhcp6-client.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/sd-dhcp6-client.c + +libsystemd_nm_la-sd-dhcp6-lease.lo: systemd/src/libsystemd-network/sd-dhcp6-lease.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-sd-dhcp6-lease.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-sd-dhcp6-lease.Tpo -c -o libsystemd_nm_la-sd-dhcp6-lease.lo `test -f 'systemd/src/libsystemd-network/sd-dhcp6-lease.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/sd-dhcp6-lease.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-sd-dhcp6-lease.Tpo $(DEPDIR)/libsystemd_nm_la-sd-dhcp6-lease.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/sd-dhcp6-lease.c' object='libsystemd_nm_la-sd-dhcp6-lease.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-sd-dhcp6-lease.lo `test -f 'systemd/src/libsystemd-network/sd-dhcp6-lease.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/sd-dhcp6-lease.c + +libsystemd_nm_la-sd-ipv4acd.lo: systemd/src/libsystemd-network/sd-ipv4acd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-sd-ipv4acd.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-sd-ipv4acd.Tpo -c -o libsystemd_nm_la-sd-ipv4acd.lo `test -f 'systemd/src/libsystemd-network/sd-ipv4acd.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/sd-ipv4acd.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-sd-ipv4acd.Tpo $(DEPDIR)/libsystemd_nm_la-sd-ipv4acd.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/sd-ipv4acd.c' object='libsystemd_nm_la-sd-ipv4acd.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-sd-ipv4acd.lo `test -f 'systemd/src/libsystemd-network/sd-ipv4acd.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/sd-ipv4acd.c + +libsystemd_nm_la-sd-ipv4ll.lo: systemd/src/libsystemd-network/sd-ipv4ll.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-sd-ipv4ll.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-sd-ipv4ll.Tpo -c -o libsystemd_nm_la-sd-ipv4ll.lo `test -f 'systemd/src/libsystemd-network/sd-ipv4ll.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/sd-ipv4ll.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-sd-ipv4ll.Tpo $(DEPDIR)/libsystemd_nm_la-sd-ipv4ll.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/sd-ipv4ll.c' object='libsystemd_nm_la-sd-ipv4ll.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-sd-ipv4ll.lo `test -f 'systemd/src/libsystemd-network/sd-ipv4ll.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/sd-ipv4ll.c + +libsystemd_nm_la-sd-lldp.lo: systemd/src/libsystemd-network/sd-lldp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-sd-lldp.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-sd-lldp.Tpo -c -o libsystemd_nm_la-sd-lldp.lo `test -f 'systemd/src/libsystemd-network/sd-lldp.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/sd-lldp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-sd-lldp.Tpo $(DEPDIR)/libsystemd_nm_la-sd-lldp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd-network/sd-lldp.c' object='libsystemd_nm_la-sd-lldp.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-sd-lldp.lo `test -f 'systemd/src/libsystemd-network/sd-lldp.c' || echo '$(srcdir)/'`systemd/src/libsystemd-network/sd-lldp.c + +libsystemd_nm_la-sd-id128.lo: systemd/src/libsystemd/sd-id128/sd-id128.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-sd-id128.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-sd-id128.Tpo -c -o libsystemd_nm_la-sd-id128.lo `test -f 'systemd/src/libsystemd/sd-id128/sd-id128.c' || echo '$(srcdir)/'`systemd/src/libsystemd/sd-id128/sd-id128.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-sd-id128.Tpo $(DEPDIR)/libsystemd_nm_la-sd-id128.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/libsystemd/sd-id128/sd-id128.c' object='libsystemd_nm_la-sd-id128.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-sd-id128.lo `test -f 'systemd/src/libsystemd/sd-id128/sd-id128.c' || echo '$(srcdir)/'`systemd/src/libsystemd/sd-id128/sd-id128.c + +libsystemd_nm_la-dns-domain.lo: systemd/src/shared/dns-domain.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsystemd_nm_la-dns-domain.lo -MD -MP -MF $(DEPDIR)/libsystemd_nm_la-dns-domain.Tpo -c -o libsystemd_nm_la-dns-domain.lo `test -f 'systemd/src/shared/dns-domain.c' || echo '$(srcdir)/'`systemd/src/shared/dns-domain.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsystemd_nm_la-dns-domain.Tpo $(DEPDIR)/libsystemd_nm_la-dns-domain.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='systemd/src/shared/dns-domain.c' object='libsystemd_nm_la-dns-domain.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsystemd_nm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsystemd_nm_la-dns-domain.lo `test -f 'systemd/src/shared/dns-domain.c' || echo '$(srcdir)/'`systemd/src/shared/dns-domain.c nm-device-bond.o: devices/nm-device-bond.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-device-bond.o -MD -MP -MF $(DEPDIR)/nm-device-bond.Tpo -c -o nm-device-bond.o `test -f 'devices/nm-device-bond.c' || echo '$(srcdir)/'`devices/nm-device-bond.c @@ -1919,20 +2147,6 @@ nm-device-ethernet.obj: devices/nm-device-ethernet.c @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-device-ethernet.obj `if test -f 'devices/nm-device-ethernet.c'; then $(CYGPATH_W) 'devices/nm-device-ethernet.c'; else $(CYGPATH_W) '$(srcdir)/devices/nm-device-ethernet.c'; fi` -nm-device-gre.o: devices/nm-device-gre.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-device-gre.o -MD -MP -MF $(DEPDIR)/nm-device-gre.Tpo -c -o nm-device-gre.o `test -f 'devices/nm-device-gre.c' || echo '$(srcdir)/'`devices/nm-device-gre.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-device-gre.Tpo $(DEPDIR)/nm-device-gre.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='devices/nm-device-gre.c' object='nm-device-gre.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-device-gre.o `test -f 'devices/nm-device-gre.c' || echo '$(srcdir)/'`devices/nm-device-gre.c - -nm-device-gre.obj: devices/nm-device-gre.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-device-gre.obj -MD -MP -MF $(DEPDIR)/nm-device-gre.Tpo -c -o nm-device-gre.obj `if test -f 'devices/nm-device-gre.c'; then $(CYGPATH_W) 'devices/nm-device-gre.c'; else $(CYGPATH_W) '$(srcdir)/devices/nm-device-gre.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-device-gre.Tpo $(DEPDIR)/nm-device-gre.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='devices/nm-device-gre.c' object='nm-device-gre.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-device-gre.obj `if test -f 'devices/nm-device-gre.c'; then $(CYGPATH_W) 'devices/nm-device-gre.c'; else $(CYGPATH_W) '$(srcdir)/devices/nm-device-gre.c'; fi` - nm-device-infiniband.o: devices/nm-device-infiniband.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-device-infiniband.o -MD -MP -MF $(DEPDIR)/nm-device-infiniband.Tpo -c -o nm-device-infiniband.o `test -f 'devices/nm-device-infiniband.c' || echo '$(srcdir)/'`devices/nm-device-infiniband.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-device-infiniband.Tpo $(DEPDIR)/nm-device-infiniband.Po @@ -1947,6 +2161,20 @@ nm-device-infiniband.obj: devices/nm-device-infiniband.c @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-device-infiniband.obj `if test -f 'devices/nm-device-infiniband.c'; then $(CYGPATH_W) 'devices/nm-device-infiniband.c'; else $(CYGPATH_W) '$(srcdir)/devices/nm-device-infiniband.c'; fi` +nm-device-ip-tunnel.o: devices/nm-device-ip-tunnel.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-device-ip-tunnel.o -MD -MP -MF $(DEPDIR)/nm-device-ip-tunnel.Tpo -c -o nm-device-ip-tunnel.o `test -f 'devices/nm-device-ip-tunnel.c' || echo '$(srcdir)/'`devices/nm-device-ip-tunnel.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-device-ip-tunnel.Tpo $(DEPDIR)/nm-device-ip-tunnel.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='devices/nm-device-ip-tunnel.c' object='nm-device-ip-tunnel.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-device-ip-tunnel.o `test -f 'devices/nm-device-ip-tunnel.c' || echo '$(srcdir)/'`devices/nm-device-ip-tunnel.c + +nm-device-ip-tunnel.obj: devices/nm-device-ip-tunnel.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-device-ip-tunnel.obj -MD -MP -MF $(DEPDIR)/nm-device-ip-tunnel.Tpo -c -o nm-device-ip-tunnel.obj `if test -f 'devices/nm-device-ip-tunnel.c'; then $(CYGPATH_W) 'devices/nm-device-ip-tunnel.c'; else $(CYGPATH_W) '$(srcdir)/devices/nm-device-ip-tunnel.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-device-ip-tunnel.Tpo $(DEPDIR)/nm-device-ip-tunnel.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='devices/nm-device-ip-tunnel.c' object='nm-device-ip-tunnel.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-device-ip-tunnel.obj `if test -f 'devices/nm-device-ip-tunnel.c'; then $(CYGPATH_W) 'devices/nm-device-ip-tunnel.c'; else $(CYGPATH_W) '$(srcdir)/devices/nm-device-ip-tunnel.c'; fi` + nm-device-macvlan.o: devices/nm-device-macvlan.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nm-device-macvlan.o -MD -MP -MF $(DEPDIR)/nm-device-macvlan.Tpo -c -o nm-device-macvlan.o `test -f 'devices/nm-device-macvlan.c' || echo '$(srcdir)/'`devices/nm-device-macvlan.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/nm-device-macvlan.Tpo $(DEPDIR)/nm-device-macvlan.Po @@ -2395,9 +2623,6 @@ uninstall-am: uninstall-dbusserviceDATA uninstall-libexecPROGRAMS \ include $(GLIB_MAKEFILE) @GNOME_CODE_COVERAGE_RULES@ - -%-glue.h: $(top_srcdir)/introspection/%.xml - $(AM_V_GEN) dbus-binding-tool --prefix=$(subst -,_,$(subst -glue.h,,$@)) --mode=glib-server --output=$@ $< install-data-hook: $(mkinstalldirs) -m 0700 $(DESTDIR)$(rundir) $(mkinstalldirs) -m 0700 $(DESTDIR)$(statedir) diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 15e03276..fb680d96 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -21,9 +21,6 @@ #include "config.h" -#include -#include -#include #include #include #include @@ -32,14 +29,15 @@ #include #include #include +#include #include #include +#include "nm-default.h" #include "NetworkManagerUtils.h" #include "nm-platform.h" #include "nm-utils.h" #include "nm-core-internal.h" -#include "nm-logging.h" #include "nm-device.h" #include "nm-setting-connection.h" #include "nm-setting-ip4-config.h" @@ -47,8 +45,6 @@ #include "nm-setting-wireless.h" #include "nm-setting-wireless-security.h" #include "nm-auth-utils.h" -#include "nm-dbus-glib-types.h" -#include "gsystem-local-alloc.h" /* * Some toolchains (E.G. uClibc 0.9.33 and earlier) don't export @@ -113,6 +109,120 @@ _nm_utils_set_testing (NMUtilsTestFlags flags) } } +/*****************************************************************************/ + +G_DEFINE_QUARK (nm-utils-error-quark, nm_utils_error) + +void +nm_utils_error_set_cancelled (GError **error, + gboolean is_disposing, + const char *instance_name) +{ + if (is_disposing) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING, + "Disposing %s instance", + instance_name && *instance_name ? instance_name : "source"); + } else { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, + "Request cancelled"); + } +} + +gboolean +nm_utils_error_is_cancelled (GError *error, + gboolean consider_is_disposing) +{ + if (error) { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return TRUE; + if ( consider_is_disposing + && g_error_matches (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING)) + return TRUE; + } + return FALSE; +} + +/*****************************************************************************/ + +static GSList *_singletons = NULL; +static gboolean _singletons_shutdown = FALSE; + +static void +_nm_singleton_instance_weak_cb (gpointer data, + GObject *where_the_object_was) +{ + _singletons = g_slist_remove (_singletons, where_the_object_was); +} + +static void __attribute__((destructor)) +_nm_singleton_instance_destroy (void) +{ + _singletons_shutdown = TRUE; + + while (_singletons) { + GObject *instance = _singletons->data; + + _singletons = g_slist_delete_link (_singletons, _singletons); + + g_object_weak_unref (instance, _nm_singleton_instance_weak_cb, NULL); + + if (instance->ref_count > 1) + nm_log_dbg (LOGD_CORE, "disown %s singleton (%p)", G_OBJECT_TYPE_NAME (instance), instance); + + g_object_unref (instance); + } +} + +void +_nm_singleton_instance_register_destruction (GObject *instance) +{ + g_return_if_fail (G_IS_OBJECT (instance)); + + /* Don't allow registration after shutdown. We only destroy the singletons + * once. */ + g_return_if_fail (!_singletons_shutdown); + + g_object_weak_ref (instance, _nm_singleton_instance_weak_cb, NULL); + + _singletons = g_slist_prepend (_singletons, instance); +} + +/*****************************************************************************/ + +gint +nm_utils_ascii_str_to_bool (const char *str, + gint default_value) +{ + gsize len; + char *s = NULL; + + if (!str) + return default_value; + + while (str[0] && g_ascii_isspace (str[0])) + str++; + + if (!str[0]) + return default_value; + + len = strlen (str); + if (g_ascii_isspace (str[len - 1])) { + s = g_strdup (str); + g_strchomp (s); + str = s; + } + + if (!g_ascii_strcasecmp (str, "true") || !g_ascii_strcasecmp (str, "yes") || !g_ascii_strcasecmp (str, "on") || !g_ascii_strcasecmp (str, "1")) + default_value = TRUE; + else if (!g_ascii_strcasecmp (str, "false") || !g_ascii_strcasecmp (str, "no") || !g_ascii_strcasecmp (str, "off") || !g_ascii_strcasecmp (str, "0")) + default_value = FALSE; + if (s) + g_free (s); + return default_value; +} + +/*****************************************************************************/ + /* * nm_ethernet_address_is_valid: * @addr: pointer to a binary or ASCII Ethernet address @@ -433,7 +543,7 @@ out: typedef struct { pid_t pid; - guint64 log_domain; + NMLogDomain log_domain; union { struct { gint64 wait_start_us; @@ -455,7 +565,7 @@ typedef struct { #define LOG_NAME_ARGS log_name,(long)pid static KillChildAsyncData * -_kc_async_data_alloc (pid_t pid, guint64 log_domain, const char *log_name, NMUtilsKillChildAsyncCb callback, void *user_data) +_kc_async_data_alloc (pid_t pid, NMLogDomain log_domain, const char *log_name, NMUtilsKillChildAsyncCb callback, void *user_data) { KillChildAsyncData *data; size_t log_name_len; @@ -570,7 +680,7 @@ _kc_invoke_callback_idle (gpointer user_data) } static void -_kc_invoke_callback (pid_t pid, guint64 log_domain, const char *log_name, NMUtilsKillChildAsyncCb callback, void *user_data, gboolean success, int child_status) +_kc_invoke_callback (pid_t pid, NMLogDomain log_domain, const char *log_name, NMUtilsKillChildAsyncCb callback, void *user_data, gboolean success, int child_status) { KillChildAsyncData *data; @@ -602,7 +712,7 @@ _kc_invoke_callback (pid_t pid, guint64 log_domain, const char *log_name, NMUtil * supports only one watcher per child. **/ void -nm_utils_kill_child_async (pid_t pid, int sig, guint64 log_domain, +nm_utils_kill_child_async (pid_t pid, int sig, NMLogDomain log_domain, const char *log_name, guint32 wait_before_kill_msec, NMUtilsKillChildAsyncCb callback, void *user_data) { @@ -707,7 +817,7 @@ _sleep_duration_convert_ms_to_us (guint32 sleep_duration_msec) * In case of error, errno is preserved to contain the last reason of failure. **/ gboolean -nm_utils_kill_child_sync (pid_t pid, int sig, guint64 log_domain, const char *log_name, +nm_utils_kill_child_sync (pid_t pid, int sig, NMLogDomain log_domain, const char *log_name, int *child_status, guint32 wait_before_kill_msec, guint32 sleep_duration_msec) { @@ -885,7 +995,7 @@ out: * process with PID @pid is gone, the process is a zombie, or @max_wait_msec expires. **/ void -nm_utils_kill_process_sync (pid_t pid, guint64 start_time, int sig, guint64 log_domain, +nm_utils_kill_process_sync (pid_t pid, guint64 start_time, int sig, NMLogDomain log_domain, const char *log_name, guint32 wait_before_kill_msec, guint32 sleep_duration_msec, guint32 max_wait_msec) { @@ -1084,6 +1194,22 @@ nm_utils_find_helper(const char *progname, const char *try_first, GError **error #define DEVICE_TYPE_TAG "type:" #define SUBCHAN_TAG "s390-subchannels:" #define EXCEPT_TAG "except:" +#define MATCH_TAG_CONFIG_NM_VERSION "nm-version:" +#define MATCH_TAG_CONFIG_NM_VERSION_MIN "nm-version-min:" +#define MATCH_TAG_CONFIG_NM_VERSION_MAX "nm-version-max:" +#define MATCH_TAG_CONFIG_ENV "env:" + +#define _spec_has_prefix(pspec, tag) \ + ({ \ + const char **_spec = (pspec); \ + gboolean _has = FALSE; \ + \ + if (!g_ascii_strncasecmp (*_spec, (""tag), STRLEN (tag))) { \ + *_spec += STRLEN (tag); \ + _has = TRUE; \ + } \ + _has; \ + }) static const char * _match_except (const char *spec_str, gboolean *out_except) @@ -1284,6 +1410,9 @@ nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels) g_return_val_if_fail (subchannels != NULL, NM_MATCH_SPEC_NO_MATCH); + if (!specs) + return NM_MATCH_SPEC_NO_MATCH; + if (!parse_subchannels (subchannels, &a, &b, &c)) return NM_MATCH_SPEC_NO_MATCH; @@ -1310,6 +1439,108 @@ nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels) return match; } +static gboolean +_match_config_nm_version (const char *str, const char *tag, guint cur_nm_version) +{ + gs_free char *s_ver = NULL; + gs_strfreev char **s_ver_tokens = NULL; + gint v_maj = -1, v_min = -1, v_mic = -1; + guint c_maj = -1, c_min = -1, c_mic = -1; + guint n_tokens; + + s_ver = g_strdup (str); + g_strstrip (s_ver); + + /* Let's be strict with the accepted format here. No funny stuff!! */ + + if (s_ver[strspn (s_ver, ".0123456789")] != '\0') + return FALSE; + + s_ver_tokens = g_strsplit (s_ver, ".", -1); + n_tokens = g_strv_length (s_ver_tokens); + if (n_tokens == 0 || n_tokens > 3) + return FALSE; + + v_maj = _nm_utils_ascii_str_to_int64 (s_ver_tokens[0], 10, 0, 0xFFFF, -1); + if (v_maj < 0) + return FALSE; + if (n_tokens >= 2) { + v_min = _nm_utils_ascii_str_to_int64 (s_ver_tokens[1], 10, 0, 0xFF, -1); + if (v_min < 0) + return FALSE; + } + if (n_tokens >= 3) { + v_mic = _nm_utils_ascii_str_to_int64 (s_ver_tokens[2], 10, 0, 0xFF, -1); + if (v_mic < 0) + return FALSE; + } + + nm_decode_version (cur_nm_version, &c_maj, &c_min, &c_mic); + +#define CHECK_AND_RETURN_FALSE(cur, val, tag, is_last_digit) \ + G_STMT_START { \ + if (!strcmp (tag, MATCH_TAG_CONFIG_NM_VERSION_MIN)) { \ + if (cur < val) \ + return FALSE; \ + } else if (!strcmp (tag, MATCH_TAG_CONFIG_NM_VERSION_MAX)) { \ + if (cur > val) \ + return FALSE; \ + } else { \ + if (cur != val) \ + return FALSE; \ + } \ + if (!(is_last_digit)) { \ + if (cur != val) \ + return FALSE; \ + } \ + } G_STMT_END + if (v_mic >= 0) + CHECK_AND_RETURN_FALSE (c_mic, v_mic, tag, TRUE); + if (v_min >= 0) + CHECK_AND_RETURN_FALSE (c_min, v_min, tag, v_mic < 0); + CHECK_AND_RETURN_FALSE (c_maj, v_maj, tag, v_min < 0); + return TRUE; +} + +NMMatchSpecMatchType +nm_match_spec_match_config (const GSList *specs, guint cur_nm_version, const char *env) +{ + const GSList *iter; + NMMatchSpecMatchType match = NM_MATCH_SPEC_NO_MATCH; + + if (!specs) + return NM_MATCH_SPEC_NO_MATCH; + + for (iter = specs; iter; iter = g_slist_next (iter)) { + const char *spec_str = iter->data; + gboolean except; + gboolean v_match; + + if (!spec_str || !*spec_str) + continue; + + spec_str = _match_except (spec_str, &except); + + if (_spec_has_prefix (&spec_str, MATCH_TAG_CONFIG_NM_VERSION)) + v_match = _match_config_nm_version (spec_str, MATCH_TAG_CONFIG_NM_VERSION, cur_nm_version); + else if (_spec_has_prefix (&spec_str, MATCH_TAG_CONFIG_NM_VERSION_MIN)) + v_match = _match_config_nm_version (spec_str, MATCH_TAG_CONFIG_NM_VERSION_MIN, cur_nm_version); + else if (_spec_has_prefix (&spec_str, MATCH_TAG_CONFIG_NM_VERSION_MAX)) + v_match = _match_config_nm_version (spec_str, MATCH_TAG_CONFIG_NM_VERSION_MAX, cur_nm_version); + else if (_spec_has_prefix (&spec_str, MATCH_TAG_CONFIG_ENV)) + v_match = env && env[0] && !strcmp (spec_str, env); + else + continue; + + if (v_match) { + if (except) + return NM_MATCH_SPEC_NEG_MATCH; + match = NM_MATCH_SPEC_MATCH; + } + } + return match; +} + /** * nm_match_spec_split: * @value: the string of device specs @@ -1495,125 +1726,229 @@ nm_match_spec_join (GSList *specs) return g_string_free (str, FALSE); } -const char * -nm_utils_get_shared_wifi_permission (NMConnection *connection) -{ - NMSettingWireless *s_wifi; - NMSettingWirelessSecurity *s_wsec; - const char *method = NULL; +/*****************************************************************************/ - method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); - if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) != 0) - return NULL; /* Not shared */ +char _nm_utils_to_string_buffer[]; - s_wifi = nm_connection_get_setting_wireless (connection); - if (s_wifi) { - s_wsec = nm_connection_get_setting_wireless_security (connection); - if (s_wsec) - return NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED; - else - return NM_AUTH_PERMISSION_WIFI_SHARE_OPEN; +void +nm_utils_to_string_buffer_init (char **buf, gsize *len) +{ + if (!*buf) { + *buf = _nm_utils_to_string_buffer; + *len = sizeof (_nm_utils_to_string_buffer); } - - return NULL; } -/*********************************/ - -static void -nm_gvalue_destroy (gpointer data) +gboolean +nm_utils_to_string_buffer_init_null (gconstpointer obj, char **buf, gsize *len) { - GValue *value = (GValue *) data; - - g_value_unset (value); - g_slice_free (GValue, value); + nm_utils_to_string_buffer_init (buf, len); + if (!obj) { + g_strlcpy (*buf, "(null)", *len); + return FALSE; + } + return TRUE; } -GHashTable * -value_hash_create (void) +void +nm_utils_strbuf_append_c (char **buf, gsize *len, char c) { - return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, nm_gvalue_destroy); + switch (*len) { + case 0: + return; + case 1: + (*buf)[0] = '\0'; + *len = 0; + (*buf)++; + return; + default: + (*buf)[0] = c; + (*buf)[1] = '\0'; + (*len)--; + (*buf)++; + return; + } } void -value_hash_add (GHashTable *hash, - const char *key, - GValue *value) +nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str) { - g_hash_table_insert (hash, g_strdup (key), value); + gsize src_len; + + switch (*len) { + case 0: + return; + case 1: + if (!str || !*str) { + (*buf)[0] = '\0'; + return; + } + (*buf)[0] = '\0'; + *len = 0; + (*buf)++; + return; + default: + if (!str || !*str) { + (*buf)[0] = '\0'; + return; + } + src_len = g_strlcpy (*buf, str, *len); + if (src_len >= *len) { + *buf = &(*buf)[*len]; + *len = 0; + } else { + *buf = &(*buf)[src_len]; + *len -= src_len; + } + return; + } } void -value_hash_add_str (GHashTable *hash, - const char *key, - const char *str) +nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) { - GValue *value; + char *p = *buf; + va_list args; + gint retval; - value = g_slice_new0 (GValue); - g_value_init (value, G_TYPE_STRING); - g_value_set_string (value, str); + if (*len == 0) + return; + + va_start (args, format); + retval = g_vsnprintf (p, *len, format, args); + va_end (args); - value_hash_add (hash, key, value); + if (retval >= *len) { + *buf = &p[*len]; + *len = 0; + } else { + *buf = &p[retval]; + *len -= retval; + } } -void -value_hash_add_object_path (GHashTable *hash, - const char *key, - const char *op) +const char * +nm_utils_flags2str (const NMUtilsFlags2StrDesc *descs, + gsize n_descs, + unsigned flags, + char *buf, + gsize len) { - GValue *value; + gsize i; + char *p; - value = g_slice_new0 (GValue); - g_value_init (value, DBUS_TYPE_G_OBJECT_PATH); - g_value_set_boxed (value, op); +#if NM_MORE_ASSERTS > 10 + nm_assert (descs); + nm_assert (n_descs > 0); + for (i = 0; i < n_descs; i++) { + gsize j; - value_hash_add (hash, key, value); -} + nm_assert (descs[i].flag && nm_utils_is_power_of_two (descs[i].flag)); + nm_assert (descs[i].name && descs[i].name[0]); + for (j = 0; j < i; j++) + nm_assert (descs[j].flag != descs[i].flag); + } +#endif -void -value_hash_add_uint (GHashTable *hash, - const char *key, - guint32 val) -{ - GValue *value; + nm_utils_to_string_buffer_init (&buf, &len); - value = g_slice_new0 (GValue); - g_value_init (value, G_TYPE_UINT); - g_value_set_uint (value, val); + if (!len) + return buf; - value_hash_add (hash, key, value); -} + buf[0] = '\0'; + if (!flags) { + return buf; + } -void -value_hash_add_bool (GHashTable *hash, - const char *key, - gboolean val) + p = buf; + for (i = 0; flags && i < n_descs; i++) { + if (NM_FLAGS_HAS (flags, descs[i].flag)) { + flags &= ~descs[i].flag; + + if (buf[0] != '\0') + nm_utils_strbuf_append_c (&p, &len, ','); + nm_utils_strbuf_append_str (&p, &len, descs[i].name); + } + } + if (flags) { + if (buf[0] != '\0') + nm_utils_strbuf_append_c (&p, &len, ','); + nm_utils_strbuf_append (&p, &len, "0x%x", flags); + } + return buf; +}; + +/*****************************************************************************/ + +const char * +nm_utils_enum2str (const NMUtilsEnum2StrDesc *descs, + gsize n_descs, + int val, + char *buf, + gsize len) { - GValue *value; + gsize i; - value = g_slice_new0 (GValue); - g_value_init (value, G_TYPE_BOOLEAN); - g_value_set_boolean (value, val); +#if NM_MORE_ASSERTS > 10 + nm_assert (descs); + nm_assert (n_descs > 0); + for (i = 0; i < n_descs; i++) { + gsize j; - value_hash_add (hash, key, value); -} + nm_assert (descs[i].name && descs[i].name[0]); + for (j = 0; j < i; j++) + nm_assert (descs[j].value != descs[i].value); + } +#endif -void -value_hash_add_object_property (GHashTable *hash, - const char *key, - GObject *object, - const char *prop, - GType val_type) + nm_utils_to_string_buffer_init (&buf, &len); + + if (!len) + return buf; + + for (i = 0; i < n_descs; i++) { + if (val == descs[i].value) { + g_strlcpy (buf, descs[i].name, len); + return buf; + } + } + + g_snprintf (buf, len, "(%d)", val); + return buf; +}; + +/*****************************************************************************/ + +/** + * nm_utils_get_shared_wifi_permission: + * @connection: the NMConnection to lookup the permission. + * + * Returns: a static string of the wifi-permission (if any) or %NULL. + */ +const char * +nm_utils_get_shared_wifi_permission (NMConnection *connection) { - GValue *value; + NMSettingWireless *s_wifi; + NMSettingWirelessSecurity *s_wsec; + const char *method = NULL; + + method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); + if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) != 0) + return NULL; /* Not shared */ - value = g_slice_new0 (GValue); - g_value_init (value, val_type); - g_object_get_property (object, prop, value); - value_hash_add (hash, key, value); + s_wifi = nm_connection_get_setting_wireless (connection); + if (s_wifi) { + s_wsec = nm_connection_get_setting_wireless_security (connection); + if (s_wsec) + return NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED; + else + return NM_AUTH_PERMISSION_WIFI_SHARE_OPEN; + } + + return NULL; } +/*********************************/ static char * get_new_connection_name (const GSList *existing, @@ -1857,6 +2192,56 @@ nm_utils_read_resolv_conf_nameservers (const char *rc_contents) return nameservers; } +/** + * nm_utils_read_resolv_conf_dns_options(): + * @rc_contents: contents of a resolv.conf; or %NULL to read /etc/resolv.conf + * + * Reads all dns options out of @rc_contents or /etc/resolv.conf and returns + * them. + * + * Returns: a #GPtrArray of 'char *' elements of each option + */ +GPtrArray * +nm_utils_read_resolv_conf_dns_options (const char *rc_contents) +{ + GPtrArray *options = NULL; + char *contents = NULL; + char **lines, **line_iter; + char **tokens, **token_iter; + char *p; + + if (rc_contents) + contents = g_strdup (rc_contents); + else { + if (!g_file_get_contents (_PATH_RESCONF, &contents, NULL, NULL)) + return NULL; + } + + options = g_ptr_array_new_full (3, g_free); + + lines = g_strsplit_set (contents, "\r\n", -1); + for (line_iter = lines; *line_iter; line_iter++) { + if (!g_str_has_prefix (*line_iter, "options")) + continue; + p = *line_iter + strlen ("options"); + if (!g_ascii_isspace (*p++)) + continue; + + tokens = g_strsplit (p, " ", 0); + for (token_iter = tokens; token_iter && *token_iter; token_iter++) { + g_strstrip (*token_iter); + if (!*token_iter[0]) + continue; + g_ptr_array_add (options, g_strdup (*token_iter)); + } + g_strfreev (tokens); + } + g_strfreev (lines); + g_free (contents); + + return options; +} + static GHashTable * check_property_in_hash (GHashTable *hash, const char *s_name, @@ -2933,7 +3318,6 @@ nm_utils_get_ipv6_interface_identifier (NMLinkType link_type, } return FALSE; } - void nm_utils_ipv6_addr_set_interface_identfier (struct in6_addr *addr, const NMUtilsIPv6IfaceId iid) @@ -2948,160 +3332,123 @@ nm_utils_ipv6_interface_identfier_get_from_addr (NMUtilsIPv6IfaceId *iid, memcpy (iid, addr->s6_addr + 8, 8); } -/** - * nm_utils_connection_hash_to_dict: - * @hash: a hashed #NMConnection - * - * Returns: a (floating) #GVariant equivalent to @hash. - */ -GVariant * -nm_utils_connection_hash_to_dict (GHashTable *hash) -{ - GValue val = { 0, }; - GVariant *variant; - - if (!hash) - return NULL; - - g_value_init (&val, DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT); - g_value_set_boxed (&val, hash); - variant = dbus_g_value_build_g_variant (&val); - g_value_unset (&val); - - return variant; -} +static gboolean +_set_stable_privacy (struct in6_addr *addr, + const char *ifname, + const char *uuid, + guint dad_counter, + gchar *secret_key, + gsize key_len, + GError **error) +{ + GChecksum *sum; + guint8 digest[32]; + guint32 tmp[2]; + gsize len = sizeof (digest); + + g_return_val_if_fail (key_len, FALSE); + + /* Documentation suggests that this can fail. + * Maybe in case of a missing algorithm in crypto library? */ + sum = g_checksum_new (G_CHECKSUM_SHA256); + if (!sum) { + g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "Can't create a SHA256 hash"); + return FALSE; + } -/** - * nm_utils_connection_dict_to_hash: - * @dict: a #GVariant-serialized #NMConnection - * - * Returns: a #GHashTable equivalent to @dict. - */ -GHashTable * -nm_utils_connection_dict_to_hash (GVariant *dict) -{ - GValue val = { 0, }; + key_len = MIN (key_len, G_MAXUINT32); - if (!dict) - return NULL; + g_checksum_update (sum, addr->s6_addr, 8); + g_checksum_update (sum, (const guchar *) ifname, strlen (ifname) + 1); + if (!uuid) + uuid = ""; + g_checksum_update (sum, (const guchar *) uuid, strlen (uuid) + 1); + tmp[0] = htonl (dad_counter); + tmp[1] = htonl (key_len); + g_checksum_update (sum, (const guchar *) tmp, sizeof (tmp)); + g_checksum_update (sum, (const guchar *) secret_key, key_len); - dbus_g_value_parse_g_variant (dict, &val); - return g_value_get_boxed (&val); -} + g_checksum_get_digest (sum, digest, &len); + g_checksum_free (sum); -GSList * -nm_utils_ip4_routes_from_gvalue (const GValue *value) -{ - GPtrArray *routes; - int i; - GSList *list = NULL; - - routes = (GPtrArray *) g_value_get_boxed (value); - for (i = 0; routes && (i < routes->len); i++) { - GArray *array = (GArray *) g_ptr_array_index (routes, i); - guint32 *array_val = (guint32 *) array->data; - NMIPRoute *route; - GError *error = NULL; - - if (array->len < 4) { - g_warning ("Ignoring invalid IP4 route"); - continue; - } + g_return_val_if_fail (len == 32, FALSE); - route = nm_ip_route_new_binary (AF_INET, - &array_val[0], array_val[1], - &array_val[2], array_val[3], - &error); - if (route) - list = g_slist_prepend (list, route); - else { - g_warning ("Ignoring invalid IP4 route: %s", error->message); - g_clear_error (&error); - } - } + memcpy (addr->s6_addr + 8, &digest[0], 8); - return g_slist_reverse (list); + return TRUE; } -static gboolean -_nm_utils_gvalue_array_validate (GValueArray *elements, guint n_expected, ...) -{ - va_list args; - GValue *tmp; - int i; - gboolean valid = FALSE; +#define RFC7217_IDGEN_RETRIES 3 +/** + * nm_utils_ipv6_addr_set_stable_privacy: + * + * Extend the address prefix with an interface identifier using the + * RFC 7217 Stable Privacy mechanism. + * + * Returns: %TRUE on success, %FALSE if the address could not be generated. + */ +gboolean +nm_utils_ipv6_addr_set_stable_privacy (struct in6_addr *addr, + const char *ifname, + const char *uuid, + guint dad_counter, + GError **error) +{ + gchar *secret_key = NULL; + gsize key_len = 0; + gboolean success = FALSE; - if (n_expected != elements->n_values) + if (dad_counter >= RFC7217_IDGEN_RETRIES) { + g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "Too many DAD collisions"); return FALSE; - - va_start (args, n_expected); - for (i = 0; i < n_expected; i++) { - tmp = g_value_array_get_nth (elements, i); - if (G_VALUE_TYPE (tmp) != va_arg (args, GType)) - goto done; } - valid = TRUE; -done: - va_end (args); - return valid; -} - -GSList * -nm_utils_ip6_routes_from_gvalue (const GValue *value) -{ - GPtrArray *routes; - int i; - GSList *list = NULL; - - routes = (GPtrArray *) g_value_get_boxed (value); - for (i = 0; routes && (i < routes->len); i++) { - GValueArray *route_values = (GValueArray *) g_ptr_array_index (routes, i); - GByteArray *dest, *next_hop; - guint prefix, metric; - NMIPRoute *route; - GError *error = NULL; - - if (!_nm_utils_gvalue_array_validate (route_values, 4, - DBUS_TYPE_G_UCHAR_ARRAY, - G_TYPE_UINT, - DBUS_TYPE_G_UCHAR_ARRAY, - G_TYPE_UINT)) { - g_warning ("Ignoring invalid IP6 route"); - continue; + /* Let's try to load a saved secret key first. */ + if (g_file_get_contents (NMSTATEDIR "/secret_key", &secret_key, &key_len, NULL)) { + if (key_len < 16) { + g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "Key is too short to be usable"); + key_len = 0; } + } else { + int urandom = open ("/dev/urandom", O_RDONLY); + mode_t key_mask; - dest = g_value_get_boxed (g_value_array_get_nth (route_values, 0)); - if (dest->len != 16) { - g_warning ("%s: ignoring invalid IP6 dest address of length %d", - __func__, dest->len); - continue; + if (!urandom) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "Can't open /dev/urandom: %s", strerror (errno)); + return FALSE; } - prefix = g_value_get_uint (g_value_array_get_nth (route_values, 1)); + /* RFC7217 mandates the key SHOULD be at least 128 bits. + * Let's use twice as much. */ + key_len = 32; + secret_key = g_malloc (key_len); - next_hop = g_value_get_boxed (g_value_array_get_nth (route_values, 2)); - if (next_hop->len != 16) { - g_warning ("%s: ignoring invalid IP6 next_hop address of length %d", - __func__, next_hop->len); - continue; + key_mask = umask (0077); + if (read (urandom, secret_key, key_len) == key_len) { + if (!g_file_set_contents (NMSTATEDIR "/secret_key", secret_key, key_len, error)) { + g_prefix_error (error, "Can't write " NMSTATEDIR "/secret_key"); + key_len = 0; + } + } else { + g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "Could not obtain a secret"); + key_len = 0; } + umask (key_mask); + close (urandom); + } - metric = g_value_get_uint (g_value_array_get_nth (route_values, 3)); - - route = nm_ip_route_new_binary (AF_INET6, - dest->data, prefix, - next_hop->data, metric, - &error); - if (route) - list = g_slist_prepend (list, route); - else { - g_warning ("Ignoring invalid IP6 route: %s", error->message); - g_clear_error (&error); - } + if (key_len) { + success = _set_stable_privacy (addr, ifname, uuid, dad_counter, + secret_key, key_len, error); } - return g_slist_reverse (list); + g_free (secret_key); + return success; } /** @@ -3121,3 +3468,78 @@ nm_utils_setpgid (gpointer unused G_GNUC_UNUSED) pid = getpid (); setpgid (pid, pid); } + +/** + * nm_utils_g_value_set_object_path: + * @value: a #GValue, initialized to store an object path + * @object: (allow-none): an #NMExportedObject + * + * Sets @value to @object's object path. If @object is %NULL, or not + * exported, @value is set to "/". + */ +void +nm_utils_g_value_set_object_path (GValue *value, gpointer object) +{ + g_return_if_fail (!object || NM_IS_EXPORTED_OBJECT (object)); + + if (object && nm_exported_object_is_exported (object)) + g_value_set_string (value, nm_exported_object_get_path (object)); + else + g_value_set_string (value, "/"); +} + +/** + * nm_utils_g_value_set_object_path_array: + * @value: a #GValue, initialized to store an object path + * @objects: a #GSList of #NMExportedObjects + * @filter_func: (allow-none): function to call on each object in @objects + * @user_data: data to pass to @filter_func + * + * Sets @value to an array of object paths of the objects in @objects. + */ +void +nm_utils_g_value_set_object_path_array (GValue *value, + GSList *objects, + NMUtilsObjectFunc filter_func, + gpointer user_data) +{ + char **paths; + guint i; + GSList *iter; + + paths = g_new (char *, g_slist_length (objects) + 1); + for (i = 0, iter = objects; iter; iter = iter->next) { + NMExportedObject *object = iter->data; + const char *path; + + path = nm_exported_object_get_path (object); + if (!path) + continue; + if (filter_func && !filter_func ((GObject *) object, user_data)) + continue; + paths[i++] = g_strdup (path); + } + paths[i] = NULL; + g_value_take_boxed (value, paths); +} + +/** + * nm_utils_g_value_set_strv: + * @value: a #GValue, initialized to store a #G_TYPE_STRV + * @strings: a #GPtrArray of strings + * + * Converts @strings to a #GStrv and stores it in @value. + */ +void +nm_utils_g_value_set_strv (GValue *value, GPtrArray *strings) +{ + char **strv; + int i; + + strv = g_new (char *, strings->len + 1); + for (i = 0; i < strings->len; i++) + strv[i] = g_strdup (strings->pdata[i]); + strv[i] = NULL; + + g_value_take_boxed (value, strv); +} diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index 1b7d924a..acd3d55a 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -22,12 +22,102 @@ #ifndef __NETWORKMANAGER_UTILS_H__ #define __NETWORKMANAGER_UTILS_H__ -#include #include #include +#include "nm-default.h" #include "nm-connection.h" -#include "nm-types.h" + +/*****************************************************************************/ + +#define NM_DEFINE_SINGLETON_INSTANCE(TYPE) \ +static TYPE *singleton_instance + +#define NM_DEFINE_SINGLETON_REGISTER(TYPE) \ +NM_DEFINE_SINGLETON_INSTANCE (TYPE); \ +static void \ +_singleton_instance_weak_ref_cb (gpointer data, \ + GObject *where_the_object_was) \ +{ \ + nm_log_dbg (LOGD_CORE, "disposing %s singleton (%p)", G_STRINGIFY (TYPE), singleton_instance); \ + singleton_instance = NULL; \ +} \ +static inline void \ +nm_singleton_instance_register (void) \ +{ \ + g_object_weak_ref (G_OBJECT (singleton_instance), _singleton_instance_weak_ref_cb, NULL); \ + _nm_singleton_instance_register_destruction (G_OBJECT (singleton_instance)); \ +} + +void _nm_singleton_instance_register_destruction (GObject *instance); + +/* By default, the getter will assert that the singleton will be created only once. You can + * change this by redefining NM_DEFINE_SINGLETON_ALLOW_MULTIPLE. */ +#ifndef NM_DEFINE_SINGLETON_ALLOW_MULTIPLE +#define NM_DEFINE_SINGLETON_ALLOW_MULTIPLE FALSE +#endif + +#define NM_DEFINE_SINGLETON_GETTER(TYPE, GETTER, GTYPE, ...) \ +NM_DEFINE_SINGLETON_INSTANCE (TYPE); \ +NM_DEFINE_SINGLETON_REGISTER (TYPE); \ +TYPE * \ +GETTER (void) \ +{ \ + if (G_UNLIKELY (!singleton_instance)) { \ + static char _already_created = FALSE; \ +\ + g_assert (!_already_created || (NM_DEFINE_SINGLETON_ALLOW_MULTIPLE)); \ + _already_created = TRUE;\ + singleton_instance = (g_object_new (GTYPE, ##__VA_ARGS__, NULL)); \ + g_assert (singleton_instance); \ + nm_singleton_instance_register (); \ + nm_log_dbg (LOGD_CORE, "create %s singleton (%p)", G_STRINGIFY (TYPE), singleton_instance); \ + } \ + return singleton_instance; \ +} + +/* attach @instance to the data or @owner. @owner owns a reference + * to @instance thus the lifetime of @instance is at least as long + * as that of @owner. Use this when @owner depends on @instance. */ +#define NM_UTILS_KEEP_ALIVE(owner, instance, unique_token) \ + G_STMT_START { \ + g_object_set_data_full (G_OBJECT (owner), \ + ".nm-utils-keep-alive-" unique_token "", \ + g_object_ref (instance), \ + g_object_unref); \ + } G_STMT_END + +/*****************************************************************************/ + +/** + * NMUtilsError: + * @NM_UTILS_ERROR_UNKNOWN: unknown or unclassified error + * @NM_UTILS_ERROR_CANCELLED_DISPOSING: when disposing an object that has + * pending aynchronous operations, the operation is cancelled with this + * error reason. Depending on the usage, this might indicate a bug because + * usually the target object should stay alive as long as there are pending + * operations. + */ +typedef enum { + NM_UTILS_ERROR_UNKNOWN = 0, /*< nick=Unknown >*/ + NM_UTILS_ERROR_CANCELLED_DISPOSING, /*< nick=CancelledDisposing >*/ +} NMUtilsError; + +#define NM_UTILS_ERROR (nm_utils_error_quark ()) +GQuark nm_utils_error_quark (void); + +void nm_utils_error_set_cancelled (GError **error, + gboolean is_disposing, + const char *instance_name); +gboolean nm_utils_error_is_cancelled (GError *error, + gboolean consider_is_disposing); + +/*****************************************************************************/ + +gint nm_utils_ascii_str_to_bool (const char *str, + gint default_value); + +/*****************************************************************************/ gboolean nm_ethernet_address_is_valid (gconstpointer addr, gssize len); @@ -97,37 +187,120 @@ NMMatchSpecMatchType nm_match_spec_device_type (const GSList *specs, const char NMMatchSpecMatchType nm_match_spec_hwaddr (const GSList *specs, const char *hwaddr); NMMatchSpecMatchType nm_match_spec_s390_subchannels (const GSList *specs, const char *subchannels); NMMatchSpecMatchType nm_match_spec_interface_name (const GSList *specs, const char *interface_name); +NMMatchSpecMatchType nm_match_spec_match_config (const GSList *specs, guint nm_version, const char *env); GSList *nm_match_spec_split (const char *value); char *nm_match_spec_join (GSList *specs); -const char *nm_utils_get_shared_wifi_permission (NMConnection *connection); +extern char _nm_utils_to_string_buffer[2096]; -GHashTable *value_hash_create (void); -void value_hash_add (GHashTable *hash, - const char *key, - GValue *value); +void nm_utils_to_string_buffer_init (char **buf, gsize *len); +gboolean nm_utils_to_string_buffer_init_null (gconstpointer obj, char **buf, gsize *len); -void value_hash_add_str (GHashTable *hash, - const char *key, - const char *str); +/*****************************************************************************/ -void value_hash_add_object_path (GHashTable *hash, - const char *key, - const char *op); +typedef struct { + unsigned flag; + const char *name; +} NMUtilsFlags2StrDesc; -void value_hash_add_uint (GHashTable *hash, - const char *key, - guint32 val); +#define NM_UTILS_FLAGS2STR(f, n) { .flag = f, .name = ""n, } -void value_hash_add_bool (GHashTable *hash, - const char *key, - gboolean val); +#define _NM_UTILS_FLAGS2STR_DEFINE(scope, fcn_name, flags_type, ...) \ +scope const char * \ +fcn_name (flags_type flags, char *buf, gsize len) \ +{ \ + static const NMUtilsFlags2StrDesc descs[] = { \ + __VA_ARGS__ \ + }; \ + G_STATIC_ASSERT (sizeof (flags_type) <= sizeof (unsigned)); \ + return nm_utils_flags2str (descs, G_N_ELEMENTS (descs), flags, buf, len); \ +}; + +#define NM_UTILS_FLAGS2STR_DEFINE(fcn_name, flags_type, ...) \ + _NM_UTILS_FLAGS2STR_DEFINE (, fcn_name, flags_type, __VA_ARGS__) +#define NM_UTILS_FLAGS2STR_DEFINE_STATIC(fcn_name, flags_type, ...) \ + _NM_UTILS_FLAGS2STR_DEFINE (static, fcn_name, flags_type, __VA_ARGS__) + +const char *nm_utils_flags2str (const NMUtilsFlags2StrDesc *descs, + gsize n_descs, + unsigned flags, + char *buf, + gsize len); + +/*****************************************************************************/ + +typedef struct { + int value; + const char *name; +} NMUtilsEnum2StrDesc; + +#define NM_UTILS_ENUM2STR(v, n) { .value = v, .name = ""n, } + +#define _NM_UTILS_ENUM2STR_DEFINE(scope, fcn_name, enum_type, ...) \ +scope const char * \ +fcn_name (enum_type val, char *buf, gsize len) \ +{ \ + static const NMUtilsEnum2StrDesc descs[] = { \ + __VA_ARGS__ \ + }; \ + G_STATIC_ASSERT (sizeof (enum_type) <= sizeof (int)); \ + return nm_utils_enum2str (descs, G_N_ELEMENTS (descs), val, buf, len); \ +} + +#define NM_UTILS_ENUM2STR_DEFINE(fcn_name, enum_type, ...) \ + _NM_UTILS_ENUM2STR_DEFINE (, fcn_name, enum_type, __VA_ARGS__) +#define NM_UTILS_ENUM2STR_DEFINE_STATIC(fcn_name, enum_type, ...) \ + _NM_UTILS_ENUM2STR_DEFINE (static, fcn_name, enum_type, __VA_ARGS__) + +const char *nm_utils_enum2str (const NMUtilsEnum2StrDesc *descs, + gsize n_descs, + int val, + char *buf, + gsize len); + +/*****************************************************************************/ + +#define _NM_UTILS_STRING_LOOKUP_TABLE_DEFINE(scope, fcn_name, lookup_type, unknown_val, ...) \ +scope const char * \ +fcn_name (lookup_type idx) \ +{ \ + static const char *const descs[] = { \ + __VA_ARGS__ \ + }; \ + if ((gssize) idx >= 0 && idx < G_N_ELEMENTS (descs)) \ + return descs[idx]; \ + return unknown_val; \ +} + +#define NM_UTILS_STRING_LOOKUP_TABLE_DEFINE(fcn_name, lookup_type, unknown_val, ...) \ + _NM_UTILS_STRING_LOOKUP_TABLE_DEFINE (, fcn_name, lookup_type, unknown_val, __VA_ARGS__) +#define NM_UTILS_STRING_LOOKUP_TABLE_DEFINE_STATIC(fcn_name, lookup_type, unknown_val, ...) \ + _NM_UTILS_STRING_LOOKUP_TABLE_DEFINE (static, fcn_name, lookup_type, unknown_val, __VA_ARGS__) + +/* Call the string-lookup-table function @fcn_name. If the function returns + * %NULL, the numeric index is converted to string using a alloca() buffer. + * Beware: this macro uses alloca(). */ +#define NM_UTILS_STRING_LOOKUP_TABLE(fcn_name, idx) \ + ({ \ + typeof (idx) _idx = (idx); \ + const char *_s; \ + \ + _s = fcn_name (_idx); \ + if (!_s) { \ + _s = g_alloca (30); \ + \ + g_snprintf ((char *) _s, 30, "(%lld)", (long long) _idx); \ + } \ + _s; \ + }) + +/*****************************************************************************/ + +void nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) __attribute__((__format__ (__printf__, 3, 4))); +void nm_utils_strbuf_append_c (char **buf, gsize *len, char c); +void nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str); -void value_hash_add_object_property (GHashTable *hash, - const char *key, - GObject *object, - const char *prop, - GType val_type); +const char *nm_utils_get_shared_wifi_permission (NMConnection *connection); const char *nm_utils_get_ip_config_method (NMConnection *connection, GType ip_setting_type); @@ -143,6 +316,7 @@ void nm_utils_complete_generic (NMConnection *connection, char *nm_utils_new_vlan_name (const char *parent_iface, guint32 vlan_id); GPtrArray *nm_utils_read_resolv_conf_nameservers (const char *rc_contents); +GPtrArray *nm_utils_read_resolv_conf_dns_options (const char *rc_contents); typedef gboolean (NMUtilsMatchFilterFunc) (NMConnection *connection, gpointer user_data); @@ -199,15 +373,15 @@ gboolean nm_utils_get_ipv6_interface_identifier (NMLinkType link_type, void nm_utils_ipv6_addr_set_interface_identfier (struct in6_addr *addr, const NMUtilsIPv6IfaceId iid); +gboolean nm_utils_ipv6_addr_set_stable_privacy (struct in6_addr *addr, + const char *ifname, + const char *uuid, + guint dad_counter, + GError **error); + void nm_utils_ipv6_interface_identfier_get_from_addr (NMUtilsIPv6IfaceId *iid, const struct in6_addr *addr); -GVariant *nm_utils_connection_hash_to_dict (GHashTable *hash); -GHashTable *nm_utils_connection_dict_to_hash (GVariant *dict); - -GSList *nm_utils_ip4_routes_from_gvalue (const GValue *value); -GSList *nm_utils_ip6_routes_from_gvalue (const GValue *value); - void nm_utils_array_remove_at_indexes (GArray *array, const guint *indexes_to_delete, gsize len); void nm_utils_setpgid (gpointer unused); @@ -232,4 +406,21 @@ gboolean nm_utils_get_testing_initialized (void); NMUtilsTestFlags nm_utils_get_testing (void); void _nm_utils_set_testing (NMUtilsTestFlags flags); +void nm_utils_g_value_set_object_path (GValue *value, gpointer object); +void nm_utils_g_value_set_strv (GValue *value, GPtrArray *strings); + +/** + * NMUtilsObjectFunc: + * @object: the object to filter on + * @user_data: data passed to the function from the caller + * + * Returns: %TRUE if the object should be used, %FALSE if not + */ +typedef gboolean (*NMUtilsObjectFunc) (GObject *object, gpointer user_data); + +void nm_utils_g_value_set_object_path_array (GValue *value, + GSList *objects, + NMUtilsObjectFunc filter_func, + gpointer user_data); + #endif /* __NETWORKMANAGER_UTILS_H__ */ diff --git a/src/devices/Makefile.am b/src/devices/Makefile.am new file mode 100644 index 00000000..3c6155b9 --- /dev/null +++ b/src/devices/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = tests diff --git a/src/devices/Makefile.in b/src/devices/Makefile.in new file mode 100644 index 00000000..4415d31b --- /dev/null +++ b/src/devices/Makefile.in @@ -0,0 +1,772 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 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 = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/devices +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) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +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) +am__DIST_COMMON = $(srcdir)/Makefile.in +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@ +AM_TESTS_FD_REDIRECT = @AM_TESTS_FD_REDIRECT@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLUEZ5_CFLAGS = @BLUEZ5_CFLAGS@ +BLUEZ5_LIBS = @BLUEZ5_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +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@ +DBUS_CFLAGS = @DBUS_CFLAGS@ +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@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ +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_CHECK_PATH = @GTKDOC_CHECK_PATH@ +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@ +KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ +LIBDL = @LIBDL@ +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@ +LOG_DRIVER = @LOG_DRIVER@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +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_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ +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@ +PERL = @PERL@ +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@ +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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ +SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ +SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ +SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ +UDEV_DIR = @UDEV_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@ +nmlibdir = @nmlibdir@ +nmrundir = @nmrundir@ +nmstatedir = @nmstatedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +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/devices/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/devices/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 + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/devices/adsl/Makefile.am b/src/devices/adsl/Makefile.am index d7457c88..e7034fa8 100644 --- a/src/devices/adsl/Makefile.am +++ b/src/devices/adsl/Makefile.am @@ -7,26 +7,16 @@ AM_CPPFLAGS = \ -I${top_builddir}/src \ -I${top_srcdir}/src/devices \ -I${top_srcdir}/src/platform \ - -I${top_srcdir}/include \ - -I$(top_builddir)/include \ + -I${top_builddir}/introspection \ + -I${top_srcdir}/shared \ + -I$(top_builddir)/shared \ -I${top_builddir}/libnm-core \ -I${top_srcdir}/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-adsl"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(DBUS_CFLAGS) \ $(GUDEV_CFLAGS) -GLIB_GENERATED = nm-adsl-enum-types.h nm-adsl-enum-types.c -GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM -GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM -nm_adsl_enum_types_sources = $(srcdir)/nm-device-adsl.h - -nm-device-adsl-glue.h: $(top_srcdir)/introspection/nm-device-adsl.xml - dbus-binding-tool --prefix=nm_device_adsl --mode=glib-server --output=$@ $< - -BUILT_SOURCES = $(GLIB_GENERATED) nm-device-adsl-glue.h - pkglib_LTLIBRARIES = libnm-device-plugin-adsl.la SYMBOL_VIS_FILE=$(srcdir)/exports.ver @@ -35,19 +25,16 @@ libnm_device_plugin_adsl_la_SOURCES = \ nm-atm-manager.c \ nm-atm-manager.h \ nm-device-adsl.c \ - nm-device-adsl.h \ - \ - $(BUILT_SOURCES) + nm-device-adsl.h libnm_device_plugin_adsl_la_LDFLAGS = \ -module -avoid-version \ -Wl,--version-script=$(SYMBOL_VIS_FILE) libnm_device_plugin_adsl_la_LIBADD = \ - $(DBUS_LIBS) \ + $(top_builddir)/introspection/libnmdbus.la \ $(GUDEV_LIBS) -CLEANFILES = $(BUILT_SOURCES) EXTRA_DIST = $(SYMBOL_VIS_FILE) if ENABLE_TESTS diff --git a/src/devices/adsl/Makefile.in b/src/devices/adsl/Makefile.in index b6e944f8..e969a627 100644 --- a/src/devices/adsl/Makefile.in +++ b/src/devices/adsl/Makefile.in @@ -140,12 +140,11 @@ am__uninstall_files_from_dir = { \ am__installdirs = "$(DESTDIR)$(pkglibdir)" LTLIBRARIES = $(pkglib_LTLIBRARIES) am__DEPENDENCIES_1 = -libnm_device_plugin_adsl_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ +libnm_device_plugin_adsl_la_DEPENDENCIES = \ + $(top_builddir)/introspection/libnmdbus.la \ $(am__DEPENDENCIES_1) -am__objects_1 = nm-adsl-enum-types.lo -am__objects_2 = $(am__objects_1) am_libnm_device_plugin_adsl_la_OBJECTS = nm-atm-manager.lo \ - nm-device-adsl.lo $(am__objects_2) + nm-device-adsl.lo libnm_device_plugin_adsl_la_OBJECTS = \ $(am_libnm_device_plugin_adsl_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) @@ -234,7 +233,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -246,8 +244,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -257,6 +253,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -311,16 +308,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -357,6 +351,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -385,7 +381,6 @@ 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@ @@ -400,6 +395,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -460,6 +457,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -467,6 +465,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -487,43 +486,34 @@ AM_CPPFLAGS = \ -I${top_builddir}/src \ -I${top_srcdir}/src/devices \ -I${top_srcdir}/src/platform \ - -I${top_srcdir}/include \ - -I$(top_builddir)/include \ + -I${top_builddir}/introspection \ + -I${top_srcdir}/shared \ + -I$(top_builddir)/shared \ -I${top_builddir}/libnm-core \ -I${top_srcdir}/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-adsl"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(DBUS_CFLAGS) \ $(GUDEV_CFLAGS) -GLIB_GENERATED = nm-adsl-enum-types.h nm-adsl-enum-types.c -GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM -GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM -nm_adsl_enum_types_sources = $(srcdir)/nm-device-adsl.h -BUILT_SOURCES = $(GLIB_GENERATED) nm-device-adsl-glue.h pkglib_LTLIBRARIES = libnm-device-plugin-adsl.la SYMBOL_VIS_FILE = $(srcdir)/exports.ver libnm_device_plugin_adsl_la_SOURCES = \ nm-atm-manager.c \ nm-atm-manager.h \ nm-device-adsl.c \ - nm-device-adsl.h \ - \ - $(BUILT_SOURCES) + nm-device-adsl.h libnm_device_plugin_adsl_la_LDFLAGS = \ -module -avoid-version \ -Wl,--version-script=$(SYMBOL_VIS_FILE) libnm_device_plugin_adsl_la_LIBADD = \ - $(DBUS_LIBS) \ + $(top_builddir)/introspection/libnmdbus.la \ $(GUDEV_LIBS) -CLEANFILES = $(BUILT_SOURCES) EXTRA_DIST = $(SYMBOL_VIS_FILE) -all: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) all-am +all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj @@ -601,7 +591,6 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-adsl-enum-types.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-atm-manager.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-device-adsl.Plo@am__quote@ @@ -717,15 +706,13 @@ distdir: $(DISTFILES) @ENABLE_TESTS_FALSE@check-local: check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-local -check: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) check-am +check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(pkglibdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done -install: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) install-am +install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am @@ -747,7 +734,6 @@ install-strip: mostlyclean-generic: clean-generic: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) @@ -756,7 +742,6 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." - -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ @@ -828,7 +813,7 @@ ps-am: uninstall-am: uninstall-pkglibLTLIBRARIES -.MAKE: all check check-am install install-am install-strip +.MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am check-local clean \ clean-generic clean-libtool clean-pkglibLTLIBRARIES \ @@ -851,9 +836,6 @@ include $(GLIB_MAKEFILE) @GNOME_CODE_COVERAGE_RULES@ -nm-device-adsl-glue.h: $(top_srcdir)/introspection/nm-device-adsl.xml - dbus-binding-tool --prefix=nm_device_adsl --mode=glib-server --output=$@ $< - @ENABLE_TESTS_TRUE@check-local: @ENABLE_TESTS_TRUE@ $(top_srcdir)/tools/check-exports.sh $(builddir)/.libs/libnm-device-plugin-adsl.so $(SYMBOL_VIS_FILE) diff --git a/src/devices/adsl/nm-adsl-enum-types.c b/src/devices/adsl/nm-adsl-enum-types.c deleted file mode 100644 index 08565331..00000000 --- a/src/devices/adsl/nm-adsl-enum-types.c +++ /dev/null @@ -1,12 +0,0 @@ - - - -/* Generated by glib-mkenums. Do not edit */ - -#include "nm-adsl-enum-types.h" - -#include "nm-device-adsl.h" - - - - diff --git a/src/devices/adsl/nm-adsl-enum-types.h b/src/devices/adsl/nm-adsl-enum-types.h deleted file mode 100644 index 88e1fe84..00000000 --- a/src/devices/adsl/nm-adsl-enum-types.h +++ /dev/null @@ -1,17 +0,0 @@ - - - -/* Generated by glib-mkenums. Do not edit */ - -#ifndef __NM_ADSL_ENUM_TYPES_H__ -#define __NM_ADSL_ENUM_TYPES_H__ - -#include - -G_BEGIN_DECLS -G_END_DECLS - -#endif /* __NM_ADSL_ENUM_TYPES_H__ */ - - - diff --git a/src/devices/adsl/nm-atm-manager.c b/src/devices/adsl/nm-atm-manager.c index aeb5af6c..d3f1423f 100644 --- a/src/devices/adsl/nm-atm-manager.c +++ b/src/devices/adsl/nm-atm-manager.c @@ -24,14 +24,12 @@ #include #include +#include "nm-default.h" #include "nm-atm-manager.h" #include "nm-setting-adsl.h" #include "nm-device-adsl.h" #include "nm-device-factory.h" -#include "nm-logging.h" -#include "nm-glib-compat.h" #include "nm-platform.h" -#include "gsystem-local-alloc.h" typedef struct { GUdevClient *client; @@ -42,7 +40,7 @@ typedef struct { static GType nm_atm_manager_get_type (void); -static void device_factory_interface_init (NMDeviceFactory *factory_iface); +static void device_factory_interface_init (NMDeviceFactoryInterface *factory_iface); G_DEFINE_TYPE_EXTENDED (NMAtmManager, nm_atm_manager, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_FACTORY, device_factory_interface_init)) @@ -239,7 +237,7 @@ nm_atm_manager_init (NMAtmManager *self) } static void -device_factory_interface_init (NMDeviceFactory *factory_iface) +device_factory_interface_init (NMDeviceFactoryInterface *factory_iface) { factory_iface->get_supported_types = get_supported_types; factory_iface->start = start; diff --git a/src/devices/adsl/nm-atm-manager.h b/src/devices/adsl/nm-atm-manager.h index e4ec3e6a..fe0bc14c 100644 --- a/src/devices/adsl/nm-atm-manager.h +++ b/src/devices/adsl/nm-atm-manager.h @@ -22,8 +22,7 @@ #ifndef __NETWORKMANAGER_ATM_MANAGER_H__ #define __NETWORKMANAGER_ATM_MANAGER_H__ -#include -#include +#include "nm-default.h" G_BEGIN_DECLS diff --git a/src/devices/adsl/nm-device-adsl-glue.h b/src/devices/adsl/nm-device-adsl-glue.h deleted file mode 100644 index 3a1b9108..00000000 --- a/src/devices/adsl/nm-device-adsl-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_adsl_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_adsl_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_adsl_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_adsl_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_adsl_object_info = { 1, - dbus_glib_nm_device_adsl_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.Adsl\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.Adsl\0Carrier\0carrier\0read\0\0" -}; - diff --git a/src/devices/adsl/nm-device-adsl.c b/src/devices/adsl/nm-device-adsl.c index bcef39a2..dd9a1203 100644 --- a/src/devices/adsl/nm-device-adsl.c +++ b/src/devices/adsl/nm-device-adsl.c @@ -29,24 +29,20 @@ #include #include -#include -#include #include #include +#include "nm-default.h" #include "nm-device-adsl.h" #include "nm-device-private.h" -#include "NetworkManagerUtils.h" -#include "nm-logging.h" #include "nm-enum-types.h" -#include "nm-dbus-manager.h" #include "nm-platform.h" #include "ppp-manager/nm-ppp-manager.h" #include "nm-setting-adsl.h" #include "nm-utils.h" -#include "nm-device-adsl-glue.h" +#include "nmdbus-device-adsl.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF (NMDeviceAdsl); @@ -238,7 +234,6 @@ link_changed_cb (NMPlatform *platform, int ifindex, NMPlatformLink *info, NMPlatformSignalChangeType change_type, - NMPlatformReason reason, NMDeviceAdsl *self) { if (change_type == NM_PLATFORM_SIGNAL_REMOVED) { @@ -264,7 +259,7 @@ pppoe_vcc_config (NMDeviceAdsl *self) NMDevice *device = NM_DEVICE (self); NMSettingAdsl *s_adsl; - s_adsl = nm_connection_get_setting_adsl (nm_device_get_connection (device)); + s_adsl = nm_connection_get_setting_adsl (nm_device_get_applied_connection (device)); g_assert (s_adsl); /* Set up the VCC */ @@ -272,7 +267,7 @@ pppoe_vcc_config (NMDeviceAdsl *self) return FALSE; /* Watch for the 'nas' interface going away */ - g_signal_connect (nm_platform_get (), NM_PLATFORM_SIGNAL_LINK_CHANGED, + g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (link_changed_cb), self); @@ -397,7 +392,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_reason) g_assert (out_reason); - s_adsl = nm_connection_get_setting_adsl (nm_device_get_connection (device)); + s_adsl = nm_connection_get_setting_adsl (nm_device_get_applied_connection (device)); g_assert (s_adsl); protocol = nm_setting_adsl_get_protocol (s_adsl); @@ -464,7 +459,7 @@ act_stage3_ip4_config_start (NMDevice *device, req = nm_device_get_act_request (device); g_assert (req); - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); g_assert (req); s_adsl = nm_connection_get_setting_adsl (connection); @@ -483,7 +478,7 @@ act_stage3_ip4_config_start (NMDevice *device, priv->ppp_manager = nm_ppp_manager_new (ppp_iface); if (nm_ppp_manager_start (priv->ppp_manager, req, nm_setting_adsl_get_username (s_adsl), 30, &err)) { - g_signal_connect (priv->ppp_manager, "state-changed", + g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_STATE_CHANGED, G_CALLBACK (ppp_state_changed), self); g_signal_connect (priv->ppp_manager, "ip4-config", @@ -494,8 +489,7 @@ act_stage3_ip4_config_start (NMDevice *device, _LOGW (LOGD_ADSL, "PPP failed to start: %s", err->message); g_error_free (err); - g_object_unref (priv->ppp_manager); - priv->ppp_manager = NULL; + nm_exported_object_clear_and_unexport (&priv->ppp_manager); *reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED; } @@ -511,10 +505,10 @@ adsl_cleanup (NMDeviceAdsl *self) if (priv->ppp_manager) { g_signal_handlers_disconnect_by_func (priv->ppp_manager, G_CALLBACK (ppp_state_changed), self); g_signal_handlers_disconnect_by_func (priv->ppp_manager, G_CALLBACK (ppp_ip4_config), self); - g_clear_object (&priv->ppp_manager); + nm_exported_object_clear_and_unexport (&priv->ppp_manager); } - g_signal_handlers_disconnect_by_func (nm_platform_get (), G_CALLBACK (link_changed_cb), self); + g_signal_handlers_disconnect_by_func (NM_PLATFORM_GET, G_CALLBACK (link_changed_cb), self); if (priv->brfd >= 0) { close (priv->brfd); @@ -666,7 +660,7 @@ nm_device_adsl_class_init (NMDeviceAdslClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_adsl_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_ADSL_SKELETON, + NULL); } diff --git a/src/devices/adsl/nm-device-adsl.h b/src/devices/adsl/nm-device-adsl.h index bf41ed79..efcdaf69 100644 --- a/src/devices/adsl/nm-device-adsl.h +++ b/src/devices/adsl/nm-device-adsl.h @@ -22,9 +22,8 @@ #ifndef __NETWORKMANAGER_DEVICE_ADSL_H__ #define __NETWORKMANAGER_DEVICE_ADSL_H__ -#include - // Parent class +#include "nm-default.h" #include "nm-device.h" G_BEGIN_DECLS diff --git a/src/devices/bluetooth/Makefile.am b/src/devices/bluetooth/Makefile.am index e6e378f0..2054ea0f 100644 --- a/src/devices/bluetooth/Makefile.am +++ b/src/devices/bluetooth/Makefile.am @@ -9,25 +9,22 @@ AM_CPPFLAGS = \ -I${top_srcdir}/src/settings \ -I${top_srcdir}/src/platform \ -I${top_srcdir}/src/devices/wwan \ - -I${top_srcdir}/include \ - -I$(top_builddir)/include \ + -I${top_builddir}/introspection \ + -I${top_srcdir}/shared \ + -I$(top_builddir)/shared \ -I${top_builddir}/libnm-core \ -I${top_srcdir}/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-bluetooth"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) + $(GLIB_CFLAGS) GLIB_GENERATED = nm-bt-enum-types.h nm-bt-enum-types.c GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM nm_bt_enum_types_sources = $(srcdir)/nm-bt-error.h -nm-device-bt-glue.h: $(top_srcdir)/introspection/nm-device-bt.xml - dbus-binding-tool --prefix=nm_device_bt --mode=glib-server --output=$@ $< - -BUILT_SOURCES = $(GLIB_GENERATED) nm-device-bt-glue.h +BUILT_SOURCES = $(GLIB_GENERATED) pkglib_LTLIBRARIES = libnm-device-plugin-bluetooth.la @@ -58,8 +55,9 @@ libnm_device_plugin_bluetooth_la_LDFLAGS = \ -Wl,--version-script=$(SYMBOL_VIS_FILE) libnm_device_plugin_bluetooth_la_LIBADD = \ + $(top_builddir)/introspection/libnmdbus.la \ $(top_builddir)/src/devices/wwan/libnm-wwan.la \ - $(DBUS_LIBS) \ + $(GLIB_LIBS) \ $(GUDEV_LIBS) if WITH_BLUEZ5_DUN diff --git a/src/devices/bluetooth/Makefile.in b/src/devices/bluetooth/Makefile.in index bdc3b5cb..f93f7242 100644 --- a/src/devices/bluetooth/Makefile.in +++ b/src/devices/bluetooth/Makefile.in @@ -148,6 +148,7 @@ LTLIBRARIES = $(pkglib_LTLIBRARIES) am__DEPENDENCIES_1 = @WITH_BLUEZ5_DUN_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) libnm_device_plugin_bluetooth_la_DEPENDENCIES = \ + $(top_builddir)/introspection/libnmdbus.la \ $(top_builddir)/src/devices/wwan/libnm-wwan.la \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_2) @@ -157,8 +158,7 @@ am__libnm_device_plugin_bluetooth_la_SOURCES_DIST = \ nm-bluez4-adapter.h nm-bluez4-manager.c nm-bluez4-manager.h \ nm-bluez5-manager.c nm-bluez5-manager.h nm-bt-error.h \ nm-bt-error.c nm-device-bt.c nm-device-bt.h nm-bt-enum-types.h \ - nm-bt-enum-types.c nm-device-bt-glue.h nm-bluez5-dun.c \ - nm-bluez5-dun.h + nm-bt-enum-types.c nm-bluez5-dun.c nm-bluez5-dun.h am__objects_1 = nm-bt-enum-types.lo am__objects_2 = $(am__objects_1) @WITH_BLUEZ5_DUN_TRUE@am__objects_3 = nm-bluez5-dun.lo @@ -254,7 +254,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -266,8 +265,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -277,6 +274,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -331,16 +329,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -377,6 +372,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -405,7 +402,6 @@ 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@ @@ -420,6 +416,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -480,6 +478,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -487,6 +486,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -505,17 +505,18 @@ with_valgrind = @with_valgrind@ AM_CPPFLAGS = -I${top_srcdir}/src -I${top_builddir}/src \ -I${top_srcdir}/src/devices -I${top_srcdir}/src/settings \ -I${top_srcdir}/src/platform -I${top_srcdir}/src/devices/wwan \ - -I${top_srcdir}/include -I$(top_builddir)/include \ - -I${top_builddir}/libnm-core -I${top_srcdir}/libnm-core \ + -I${top_builddir}/introspection -I${top_srcdir}/shared \ + -I$(top_builddir)/shared -I${top_builddir}/libnm-core \ + -I${top_srcdir}/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-bluetooth"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) $(am__append_1) + $(am__append_1) GLIB_GENERATED = nm-bt-enum-types.h nm-bt-enum-types.c GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM nm_bt_enum_types_sources = $(srcdir)/nm-bt-error.h -BUILT_SOURCES = $(GLIB_GENERATED) nm-device-bt-glue.h +BUILT_SOURCES = $(GLIB_GENERATED) pkglib_LTLIBRARIES = libnm-device-plugin-bluetooth.la SYMBOL_VIS_FILE = $(srcdir)/exports.ver libnm_device_plugin_bluetooth_la_SOURCES = nm-bluez-manager.c \ @@ -529,7 +530,8 @@ libnm_device_plugin_bluetooth_la_LDFLAGS = \ -Wl,--version-script=$(SYMBOL_VIS_FILE) libnm_device_plugin_bluetooth_la_LIBADD = \ - $(top_builddir)/src/devices/wwan/libnm-wwan.la $(DBUS_LIBS) \ + $(top_builddir)/introspection/libnmdbus.la \ + $(top_builddir)/src/devices/wwan/libnm-wwan.la $(GLIB_LIBS) \ $(GUDEV_LIBS) $(am__append_3) CLEANFILES = $(BUILT_SOURCES) EXTRA_DIST = $(SYMBOL_VIS_FILE) @@ -868,9 +870,6 @@ include $(GLIB_MAKEFILE) @GNOME_CODE_COVERAGE_RULES@ -nm-device-bt-glue.h: $(top_srcdir)/introspection/nm-device-bt.xml - dbus-binding-tool --prefix=nm_device_bt --mode=glib-server --output=$@ $< - @ENABLE_TESTS_TRUE@check-local: @ENABLE_TESTS_TRUE@ $(top_srcdir)/tools/check-exports.sh $(builddir)/.libs/libnm-device-plugin-bluetooth.so $(SYMBOL_VIS_FILE) diff --git a/src/devices/bluetooth/nm-bluez-common.h b/src/devices/bluetooth/nm-bluez-common.h index f0cab43b..4262fa76 100644 --- a/src/devices/bluetooth/nm-bluez-common.h +++ b/src/devices/bluetooth/nm-bluez-common.h @@ -21,7 +21,7 @@ #ifndef __NETWORKMANAGER_BLUEZ_COMMON_H__ #define __NETWORKMANAGER_BLUEZ_COMMON_H__ -#include +#include "config.h" #define BLUETOOTH_CONNECT_DUN "dun" #define BLUETOOTH_CONNECT_NAP "nap" diff --git a/src/devices/bluetooth/nm-bluez-device.c b/src/devices/bluetooth/nm-bluez-device.c index 89ad8270..b7032143 100644 --- a/src/devices/bluetooth/nm-bluez-device.c +++ b/src/devices/bluetooth/nm-bluez-device.c @@ -21,17 +21,14 @@ #include "config.h" -#include -#include -#include #include +#include "nm-default.h" #include "nm-core-internal.h" #include "nm-bt-error.h" #include "nm-bluez-common.h" #include "nm-bluez-device.h" -#include "nm-logging.h" #include "nm-settings-connection.h" #include "NetworkManagerUtils.h" @@ -869,21 +866,14 @@ properties_changed (GDBusProxy *proxy, static void bluez4_property_changed (GDBusProxy *proxy, - const char *sender, - const char *signal_name, - GVariant *parameters, - gpointer user_data) + const char *property, + GVariant *v, + gpointer user_data) { NMBluezDevice *self = NM_BLUEZ_DEVICE (user_data); - if (g_strcmp0 (signal_name, "PropertyChanged") == 0) { - const char *property = NULL; - GVariant *v = NULL; - - g_variant_get (parameters, "(&sv)", &property, &v); - _take_one_variant_property (self, property, v); - check_emit_usable (self); - } + _take_one_variant_property (self, property, v); + check_emit_usable (self); } static void @@ -893,27 +883,22 @@ get_properties_cb_4 (GObject *source_object, GAsyncResult *res, gpointer user_da NMBluezDevicePrivate *priv = NM_BLUEZ_DEVICE_GET_PRIVATE (self); GError *err = NULL; GVariant *v_properties, *v_dict; - GVariantType *v_type; - v_properties = g_dbus_proxy_call_finish (priv->proxy, res, &err); + v_properties = _nm_dbus_proxy_call_finish (priv->proxy, res, + G_VARIANT_TYPE ("(a{sv})"), + &err); if (!v_properties) { + g_dbus_error_strip_remote_error (err); nm_log_warn (LOGD_BT, "bluez[%s] error getting device properties: %s", - priv->path, err && err->message ? err->message : "(unknown)"); + priv->path, err->message); g_error_free (err); g_signal_emit (self, signals[INITIALIZED], 0, FALSE); goto END; } - v_type = g_variant_type_new ("(a{sv})"); - if (g_variant_is_of_type (v_properties, v_type)) { - v_dict = g_variant_get_child_value (v_properties, 0); - _set_properties (self, v_dict); - g_variant_unref (v_dict); - } else { - nm_log_warn (LOGD_BT, "bluez[%s] GetProperties returns unexpected result of type %s", priv->path, g_variant_get_type_string (v_properties)); - } - g_variant_type_free (v_type); - + v_dict = g_variant_get_child_value (v_properties, 0); + _set_properties (self, v_dict); + g_variant_unref (v_dict); g_variant_unref (v_properties); /* Check if any connections match this device */ @@ -922,7 +907,6 @@ get_properties_cb_4 (GObject *source_object, GAsyncResult *res, gpointer user_da priv->initialized = TRUE; g_signal_emit (self, signals[INITIALIZED], 0, TRUE); - check_emit_usable (self); END: @@ -990,8 +974,8 @@ on_proxy_acquired (GObject *object, GAsyncResult *res, NMBluezDevice *self) G_CALLBACK (properties_changed), self); if (priv->bluez_version == 4) { /* Watch for custom Bluez4 PropertyChanged signals */ - g_signal_connect (priv->proxy, "g-signal", - G_CALLBACK (bluez4_property_changed), self); + _nm_dbus_signal_connect (priv->proxy, "PropertyChanged", G_VARIANT_TYPE ("(sv)"), + G_CALLBACK (bluez4_property_changed), self); } query_properties (self); diff --git a/src/devices/bluetooth/nm-bluez-device.h b/src/devices/bluetooth/nm-bluez-device.h index 92d99fa7..0e54fcb0 100644 --- a/src/devices/bluetooth/nm-bluez-device.h +++ b/src/devices/bluetooth/nm-bluez-device.h @@ -21,11 +21,9 @@ #ifndef __NETWORKMANAGER_BLUEZ_DEVICE_H__ #define __NETWORKMANAGER_BLUEZ_DEVICE_H__ -#include -#include -#include -#include +#include "config.h" +#include "nm-default.h" #include "nm-connection.h" #include "nm-connection-provider.h" diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c index df4eb46d..6903356c 100644 --- a/src/devices/bluetooth/nm-bluez-manager.c +++ b/src/devices/bluetooth/nm-bluez-manager.c @@ -24,9 +24,8 @@ #include #include #include -#include -#include "nm-logging.h" +#include "nm-default.h" #include "nm-bluez-manager.h" #include "nm-device-factory.h" #include "nm-setting-bluetooth.h" @@ -36,9 +35,9 @@ #include "nm-bluez-common.h" #include "nm-connection-provider.h" #include "nm-device-bt.h" - -#include "nm-dbus-manager.h" +#include "nm-core-internal.h" #include "nm-platform.h" +#include "nm-dbus-compat.h" typedef struct { int bluez_version; @@ -57,7 +56,7 @@ typedef struct { static GType nm_bluez_manager_get_type (void); -static void device_factory_interface_init (NMDeviceFactory *factory_iface); +static void device_factory_interface_init (NMDeviceFactoryInterface *factory_iface); G_DEFINE_TYPE_EXTENDED (NMBluezManager, nm_bluez_manager, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_FACTORY, device_factory_interface_init)) @@ -278,10 +277,13 @@ check_bluez_and_try_setup_do_introspect (GObject *source_object, g_clear_object (&priv->async_cancellable); - result = g_dbus_proxy_call_finish (priv->introspect_proxy, res, &error); - + result = _nm_dbus_proxy_call_finish (priv->introspect_proxy, res, + G_VARIANT_TYPE ("(s)"), &error); if (!result) { - char *reason2 = g_strdup_printf ("introspect failed with %s", error->message); + char *reason2; + + g_dbus_error_strip_remote_error (error); + reason2 = g_strdup_printf ("introspect failed with %s", error->message); check_bluez_and_try_setup_final_step (self, 0, reason2); g_error_free (error); g_free (reason2); @@ -407,7 +409,11 @@ nm_bluez_manager_init (NMBluezManager *self) } static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) { g_warn_if_fail (plink->type == NM_LINK_TYPE_BNEP); *out_ignore = TRUE; @@ -415,10 +421,10 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, } static void -device_factory_interface_init (NMDeviceFactory *factory_iface) +device_factory_interface_init (NMDeviceFactoryInterface *factory_iface) { factory_iface->get_supported_types = get_supported_types; - factory_iface->new_link = new_link; + factory_iface->create_device = create_device; factory_iface->start = start; } diff --git a/src/devices/bluetooth/nm-bluez-manager.h b/src/devices/bluetooth/nm-bluez-manager.h index 8320b298..1f5597d8 100644 --- a/src/devices/bluetooth/nm-bluez-manager.h +++ b/src/devices/bluetooth/nm-bluez-manager.h @@ -22,8 +22,7 @@ #ifndef __NETWORKMANAGER_BLUEZ_MANAGER_H__ #define __NETWORKMANAGER_BLUEZ_MANAGER_H__ -#include -#include +#include "nm-default.h" G_BEGIN_DECLS diff --git a/src/devices/bluetooth/nm-bluez4-adapter.c b/src/devices/bluetooth/nm-bluez4-adapter.c index 9d1cfe1f..04ae833a 100644 --- a/src/devices/bluetooth/nm-bluez4-adapter.c +++ b/src/devices/bluetooth/nm-bluez4-adapter.c @@ -20,17 +20,14 @@ #include "config.h" -#include #include +#include "nm-default.h" #include "nm-dbus-interface.h" -#include "nm-dbus-manager.h" #include "nm-bluez4-adapter.h" #include "nm-bluez-device.h" #include "nm-bluez-common.h" -#include "nm-dbus-glib-types.h" -#include "nm-logging.h" - +#include "nm-core-internal.h" G_DEFINE_TYPE (NMBluez4Adapter, nm_bluez4_adapter, G_TYPE_OBJECT) @@ -38,7 +35,7 @@ G_DEFINE_TYPE (NMBluez4Adapter, nm_bluez4_adapter, G_TYPE_OBJECT) typedef struct { char *path; - DBusGProxy *proxy; + GDBusProxy *proxy; gboolean initialized; char *address; @@ -158,7 +155,7 @@ device_do_remove (NMBluez4Adapter *self, NMBluezDevice *device) } static void -device_created (DBusGProxy *proxy, const char *path, gpointer user_data) +device_created (GDBusProxy *proxy, const char *path, gpointer user_data) { NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); @@ -173,7 +170,7 @@ device_created (DBusGProxy *proxy, const char *path, gpointer user_data) } static void -device_removed (DBusGProxy *proxy, const char *path, gpointer user_data) +device_removed (GDBusProxy *proxy, const char *path, gpointer user_data) { NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); @@ -186,37 +183,36 @@ device_removed (DBusGProxy *proxy, const char *path, gpointer user_data) device_do_remove (self, device); } - static void -get_properties_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +get_properties_cb (GObject *proxy, GAsyncResult *result, gpointer user_data) { NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); - GHashTable *properties = NULL; GError *err = NULL; - GValue *value; - GPtrArray *devices; + GVariant *ret, *properties; + char **devices; int i; - if (!dbus_g_proxy_end_call (proxy, call, &err, - DBUS_TYPE_G_MAP_OF_VARIANT, &properties, - G_TYPE_INVALID)) { - nm_log_warn (LOGD_BT, "bluez error getting adapter properties: %s", - err && err->message ? err->message : "(unknown)"); + ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result, + G_VARIANT_TYPE ("(a{sv})"), &err); + if (!ret) { + g_dbus_error_strip_remote_error (err); + nm_log_warn (LOGD_BT, "bluez error getting adapter properties: %s", err->message); g_error_free (err); goto done; } - value = g_hash_table_lookup (properties, "Address"); - priv->address = value ? g_value_dup_string (value) : NULL; - - value = g_hash_table_lookup (properties, "Devices"); - devices = value ? g_value_get_boxed (value) : NULL; + properties = g_variant_get_child_value (ret, 0); - for (i = 0; devices && i < devices->len; i++) - device_created (priv->proxy, g_ptr_array_index (devices, i), self); + g_variant_lookup (properties, "Address", "s", &priv->address); + if (g_variant_lookup (properties, "Devices", "^ao", &devices)) { + for (i = 0; devices[i]; i++) + device_created (priv->proxy, devices[i], self); + g_strfreev (devices); + } - g_hash_table_unref (properties); + g_variant_unref (properties); + g_variant_unref (ret); priv->initialized = TRUE; @@ -228,16 +224,12 @@ static void query_properties (NMBluez4Adapter *self) { NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); - DBusGProxyCall *call; - - call = dbus_g_proxy_begin_call (priv->proxy, "GetProperties", - get_properties_cb, - self, - NULL, G_TYPE_INVALID); - if (!call) { - nm_log_warn (LOGD_BT, "failed to request Bluetooth adapter properties for %s.", - priv->path); - } + + g_dbus_proxy_call (priv->proxy, "GetProperties", + NULL, + G_DBUS_CALL_FLAGS_NONE, -1, + NULL, + get_properties_cb, self); } /***********************************************************/ @@ -247,34 +239,25 @@ nm_bluez4_adapter_new (const char *path, NMConnectionProvider *provider) { NMBluez4Adapter *self; NMBluez4AdapterPrivate *priv; - DBusGConnection *connection; self = (NMBluez4Adapter *) g_object_new (NM_TYPE_BLUEZ4_ADAPTER, NM_BLUEZ4_ADAPTER_PATH, path, NULL); - if (!self) - return NULL; - priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); priv->provider = provider; - connection = nm_dbus_manager_get_connection (nm_dbus_manager_get ()); - - priv->proxy = dbus_g_proxy_new_for_name (connection, - BLUEZ_SERVICE, - priv->path, - BLUEZ4_ADAPTER_INTERFACE); - - dbus_g_proxy_add_signal (priv->proxy, "DeviceCreated", - DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "DeviceCreated", - G_CALLBACK (device_created), self, NULL); - - dbus_g_proxy_add_signal (priv->proxy, "DeviceRemoved", - DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "DeviceRemoved", - G_CALLBACK (device_removed), self, NULL); + priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, + BLUEZ_SERVICE, + priv->path, + BLUEZ4_ADAPTER_INTERFACE, + NULL, NULL); + _nm_dbus_signal_connect (priv->proxy, "DeviceCreated", G_VARIANT_TYPE ("(o)"), + G_CALLBACK (device_created), self); + _nm_dbus_signal_connect (priv->proxy, "DeviceRemoved", G_VARIANT_TYPE ("(o)"), + G_CALLBACK (device_removed), self); query_properties (self); return self; diff --git a/src/devices/bluetooth/nm-bluez4-adapter.h b/src/devices/bluetooth/nm-bluez4-adapter.h index a6256412..a8a2bfb4 100644 --- a/src/devices/bluetooth/nm-bluez4-adapter.h +++ b/src/devices/bluetooth/nm-bluez4-adapter.h @@ -21,9 +21,8 @@ #ifndef __NETWORKMANAGER_BLUEZ4_ADAPTER_H__ #define __NETWORKMANAGER_BLUEZ4_ADAPTER_H__ -#include -#include +#include "nm-default.h" #include "nm-bluez-device.h" #include "nm-connection-provider.h" diff --git a/src/devices/bluetooth/nm-bluez4-manager.c b/src/devices/bluetooth/nm-bluez4-manager.c index 23b13d32..c5ba120c 100644 --- a/src/devices/bluetooth/nm-bluez4-manager.c +++ b/src/devices/bluetooth/nm-bluez4-manager.c @@ -24,24 +24,20 @@ #include #include #include -#include -#include "nm-logging.h" -#include "nm-dbus-glib-types.h" +#include "nm-default.h" #include "nm-bluez-manager.h" #include "nm-bluez4-manager.h" #include "nm-bluez4-adapter.h" -#include "nm-dbus-manager.h" #include "nm-bluez-common.h" - +#include "nm-core-internal.h" typedef struct { - NMDBusManager *dbus_mgr; gulong name_owner_changed_id; NMConnectionProvider *provider; - DBusGProxy *proxy; + GDBusProxy *proxy; NMBluez4Adapter *adapter; } NMBluez4ManagerPrivate; @@ -120,7 +116,7 @@ adapter_initialized (NMBluez4Adapter *adapter, gboolean success, gpointer user_d } static void -adapter_removed (DBusGProxy *proxy, const char *path, NMBluez4Manager *self) +adapter_removed (GDBusProxy *proxy, const char *path, NMBluez4Manager *self) { NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); @@ -140,7 +136,7 @@ adapter_removed (DBusGProxy *proxy, const char *path, NMBluez4Manager *self) } static void -default_adapter_changed (DBusGProxy *proxy, const char *path, NMBluez4Manager *self) +default_adapter_changed (GDBusProxy *proxy, const char *path, NMBluez4Manager *self) { NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); const char *cur_path = NULL; @@ -166,130 +162,65 @@ default_adapter_changed (DBusGProxy *proxy, const char *path, NMBluez4Manager *s } static void -default_adapter_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +default_adapter_cb (GObject *proxy, GAsyncResult *result, gpointer user_data) { NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data); NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - const char *default_adapter = NULL; + GVariant *ret; GError *err = NULL; - if (!dbus_g_proxy_end_call (proxy, call, &err, - DBUS_TYPE_G_OBJECT_PATH, &default_adapter, - G_TYPE_INVALID)) { + ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result, + G_VARIANT_TYPE ("(o)"), &err); + if (ret) { + const char *default_adapter; + + g_variant_get (ret, "(&o)", &default_adapter); + default_adapter_changed (priv->proxy, default_adapter, self); + g_variant_unref (ret); + } else { /* Ignore "No such adapter" errors; just means bluetooth isn't active */ - if ( !dbus_g_error_has_name (err, "org.bluez.Error.NoSuchAdapter") - && !dbus_g_error_has_name (err, "org.freedesktop.systemd1.LoadFailed") - && !g_error_matches (err, DBUS_GERROR, DBUS_GERROR_SERVICE_UNKNOWN)) { + if ( !_nm_dbus_error_has_name (err, "org.bluez.Error.NoSuchAdapter") + && !_nm_dbus_error_has_name (err, "org.freedesktop.systemd1.LoadFailed") + && !g_error_matches (err, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { + g_dbus_error_strip_remote_error (err); nm_log_warn (LOGD_BT, "bluez error getting default adapter: %s", - err && err->message ? err->message : "(unknown)"); + err->message); } g_error_free (err); - return; } - - default_adapter_changed (priv->proxy, default_adapter, self); } static void query_default_adapter (NMBluez4Manager *self) { NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - DBusGProxyCall *call; - - call = dbus_g_proxy_begin_call (priv->proxy, "DefaultAdapter", - default_adapter_cb, - self, - NULL, G_TYPE_INVALID); - if (!call) - nm_log_warn (LOGD_BT, "failed to request default Bluetooth adapter."); -} - -static void -bluez_connect (NMBluez4Manager *self) -{ - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - DBusGConnection *connection; - - g_return_if_fail (priv->proxy == NULL); - connection = nm_dbus_manager_get_connection (priv->dbus_mgr); - if (!connection) - return; - - priv->proxy = dbus_g_proxy_new_for_name (connection, - BLUEZ_SERVICE, - BLUEZ_MANAGER_PATH, - BLUEZ4_MANAGER_INTERFACE); - - dbus_g_proxy_add_signal (priv->proxy, "AdapterRemoved", - DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "AdapterRemoved", - G_CALLBACK (adapter_removed), self, NULL); - - dbus_g_proxy_add_signal (priv->proxy, "DefaultAdapterChanged", - DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "DefaultAdapterChanged", - G_CALLBACK (default_adapter_changed), self, NULL); - - query_default_adapter (self); + g_dbus_proxy_call (priv->proxy, "DefaultAdapter", + NULL, + G_DBUS_CALL_FLAGS_NONE, -1, + NULL, + default_adapter_cb, self); } static void -name_owner_changed_cb (NMDBusManager *dbus_mgr, - const char *name, - const char *old_owner, - const char *new_owner, +name_owner_changed_cb (GObject *object, + GParamSpec *pspec, gpointer user_data) { NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data); NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - gboolean old_owner_good = (old_owner && strlen (old_owner)); - gboolean new_owner_good = (new_owner && strlen (new_owner)); + char *owner; - /* Can't handle the signal if its not from the Bluez */ - if (strcmp (BLUEZ_SERVICE, name)) - return; - - if (!old_owner_good && new_owner_good) + owner = g_dbus_proxy_get_name_owner (priv->proxy); + if (owner) { query_default_adapter (self); - else if (old_owner_good && !new_owner_good) { + g_free (owner); + } else { /* Throwing away the adapter removes all devices too */ - if (priv->adapter) { - g_object_unref (priv->adapter); - priv->adapter = NULL; - } + g_clear_object (&priv->adapter); } } -static void -bluez_cleanup (NMBluez4Manager *self, gboolean do_signal) -{ - NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - - if (priv->proxy) { - g_object_unref (priv->proxy); - priv->proxy = NULL; - } - - if (priv->adapter) { - g_object_unref (priv->adapter); - priv->adapter = NULL; - } -} - -static void -dbus_connection_changed_cb (NMDBusManager *dbus_mgr, - DBusGConnection *connection, - gpointer user_data) -{ - NMBluez4Manager *self = NM_BLUEZ4_MANAGER (user_data); - - if (!connection) - bluez_cleanup (self, TRUE); - else - bluez_connect (self); -} - /****************************************************************/ NMBluez4Manager * @@ -307,20 +238,21 @@ nm_bluez4_manager_init (NMBluez4Manager *self) { NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - priv->dbus_mgr = nm_dbus_manager_get (); - g_assert (priv->dbus_mgr); + priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, + BLUEZ_SERVICE, + BLUEZ_MANAGER_PATH, + BLUEZ4_MANAGER_INTERFACE, + NULL, NULL); + _nm_dbus_signal_connect (priv->proxy, "AdapterRemoved", G_VARIANT_TYPE ("(o)"), + G_CALLBACK (adapter_removed), self); + _nm_dbus_signal_connect (priv->proxy, "DefaultAdapterChanged", G_VARIANT_TYPE ("(o)"), + G_CALLBACK (default_adapter_changed), self); + g_signal_connect (priv->proxy, "notify::g-name-owner", + G_CALLBACK (name_owner_changed_cb), self); - g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_NAME_OWNER_CHANGED, - G_CALLBACK (name_owner_changed_cb), - self); - - g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED, - G_CALLBACK (dbus_connection_changed_cb), - self); - - bluez_connect (self); + query_default_adapter (self); } static void @@ -329,13 +261,8 @@ dispose (GObject *object) NMBluez4Manager *self = NM_BLUEZ4_MANAGER (object); NMBluez4ManagerPrivate *priv = NM_BLUEZ4_MANAGER_GET_PRIVATE (self); - bluez_cleanup (self, FALSE); - - if (priv->dbus_mgr) { - g_signal_handlers_disconnect_by_func (priv->dbus_mgr, name_owner_changed_cb, self); - g_signal_handlers_disconnect_by_func (priv->dbus_mgr, dbus_connection_changed_cb, self); - priv->dbus_mgr = NULL; - } + g_clear_object (&priv->proxy); + g_clear_object (&priv->adapter); G_OBJECT_CLASS (nm_bluez4_manager_parent_class)->dispose (object); } diff --git a/src/devices/bluetooth/nm-bluez4-manager.h b/src/devices/bluetooth/nm-bluez4-manager.h index 13cfef93..f6bf7658 100644 --- a/src/devices/bluetooth/nm-bluez4-manager.h +++ b/src/devices/bluetooth/nm-bluez4-manager.h @@ -22,11 +22,8 @@ #ifndef __NETWORKMANAGER_BLUEZ4_MANAGER_H__ #define __NETWORKMANAGER_BLUEZ4_MANAGER_H__ -#include -#include - -#include -#include "nm-connection-provider.h" +#include "nm-default.h" +#include "nm-connection-provider.h" G_BEGIN_DECLS diff --git a/src/devices/bluetooth/nm-bluez5-dun.c b/src/devices/bluetooth/nm-bluez5-dun.c index a97eaa77..875a662f 100644 --- a/src/devices/bluetooth/nm-bluez5-dun.c +++ b/src/devices/bluetooth/nm-bluez5-dun.c @@ -32,7 +32,7 @@ #include "nm-bluez5-dun.h" #include "nm-bt-error.h" -#include "nm-logging.h" +#include "nm-default.h" #include "NetworkManagerUtils.h" struct _NMBluez5DunContext { @@ -137,10 +137,7 @@ sdp_search_cleanup (NMBluez5DunContext *context) context->sdp_session = NULL; } - if (context->sdp_watch_id) { - g_source_remove (context->sdp_watch_id); - context->sdp_watch_id = 0; - } + nm_clear_g_source (&context->sdp_watch_id); } static void diff --git a/src/devices/bluetooth/nm-bluez5-dun.h b/src/devices/bluetooth/nm-bluez5-dun.h index 7e259725..c59cbb80 100644 --- a/src/devices/bluetooth/nm-bluez5-dun.h +++ b/src/devices/bluetooth/nm-bluez5-dun.h @@ -21,8 +21,7 @@ #ifndef _NM_BLUEZ5_UTILS_H_ #define _NM_BLUEZ5_UTILS_H_ -#include -#include +#include "nm-default.h" typedef struct _NMBluez5DunContext NMBluez5DunContext; diff --git a/src/devices/bluetooth/nm-bluez5-manager.c b/src/devices/bluetooth/nm-bluez5-manager.c index b8568523..c9f5828d 100644 --- a/src/devices/bluetooth/nm-bluez5-manager.c +++ b/src/devices/bluetooth/nm-bluez5-manager.c @@ -25,20 +25,16 @@ #include #include #include -#include -#include "nm-logging.h" +#include "nm-default.h" #include "nm-bluez-manager.h" #include "nm-bluez5-manager.h" #include "nm-bluez-device.h" #include "nm-bluez-common.h" -#include "nm-dbus-manager.h" +#include "nm-core-internal.h" typedef struct { - NMDBusManager *dbus_mgr; - gulong name_owner_changed_id; - NMConnectionProvider *provider; GDBusProxy *proxy; @@ -170,39 +166,23 @@ device_removed (GDBusProxy *proxy, const gchar *path, NMBluez5Manager *self) } static void -object_manager_g_signal (GDBusProxy *proxy, - gchar *sender_name, - gchar *signal_name, - GVariant *parameters, - NMBluez5Manager *self) +object_manager_interfaces_added (GDBusProxy *proxy, + const char *path, + GVariant *dict, + NMBluez5Manager *self) { - GVariant *variant; - const gchar *path; - - if (!strcmp (signal_name, "InterfacesRemoved")) { - const gchar **ifaces; - gsize i, length; - - g_variant_get (parameters, "(&o*)", &path, &variant); - - ifaces = g_variant_get_strv (variant, &length); - - for (i = 0; i < length; i++) { - if (!strcmp (ifaces[i], BLUEZ5_DEVICE_INTERFACE)) { - device_removed (proxy, path, self); - break; - } - } - - g_free (ifaces); - - } else if (!strcmp (signal_name, "InterfacesAdded")) { - g_variant_get (parameters, "(&o*)", &path, &variant); + if (g_variant_lookup (dict, BLUEZ5_DEVICE_INTERFACE, "a{sv}", NULL)) + device_added (proxy, path, self); +} - if (g_variant_lookup_value (variant, BLUEZ5_DEVICE_INTERFACE, - G_VARIANT_TYPE_DICTIONARY)) - device_added (proxy, path, self); - } +static void +object_manager_interfaces_removed (GDBusProxy *proxy, + const char *path, + const char **ifaces, + NMBluez5Manager *self) +{ + if (_nm_utils_string_in_list (BLUEZ5_DEVICE_INTERFACE, ifaces)) + device_removed (proxy, path, self); } static void @@ -215,14 +195,15 @@ get_managed_objects_cb (GDBusProxy *proxy, GError *error = NULL; const char *path; - variant = g_dbus_proxy_call_finish (proxy, res, &error); - + variant = _nm_dbus_proxy_call_finish (proxy, res, + G_VARIANT_TYPE ("(a{oa{sa{sv}}})"), + &error); if (!variant) { if (g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) nm_log_warn (LOGD_BT, "Couldn't get managed objects: not running Bluez5?"); else { - nm_log_warn (LOGD_BT, "Couldn't get managed objects: %s", - error && error->message ? error->message : "(unknown)"); + g_dbus_error_strip_remote_error (error); + nm_log_warn (LOGD_BT, "Couldn't get managed objects: %s", error->message); } g_clear_error (&error); return; @@ -238,6 +219,8 @@ get_managed_objects_cb (GDBusProxy *proxy, g_variant_unref (variant); } +static void name_owner_changed_cb (GObject *object, GParamSpec *pspec, gpointer user_data); + static void on_proxy_acquired (GObject *object, GAsyncResult *res, @@ -255,6 +238,9 @@ on_proxy_acquired (GObject *object, return; } + g_signal_connect (priv->proxy, "notify::g-name-owner", + G_CALLBACK (name_owner_changed_cb), self); + /* Get already managed devices. */ g_dbus_proxy_call (priv->proxy, "GetManagedObjects", NULL, @@ -264,8 +250,10 @@ on_proxy_acquired (GObject *object, (GAsyncReadyCallback) get_managed_objects_cb, self); - g_signal_connect (priv->proxy, "g-signal", - G_CALLBACK (object_manager_g_signal), self); + _nm_dbus_signal_connect (priv->proxy, "InterfacesAdded", G_VARIANT_TYPE ("(oa{sa{sv}})"), + G_CALLBACK (object_manager_interfaces_added), self); + _nm_dbus_signal_connect (priv->proxy, "InterfacesRemoved", G_VARIANT_TYPE ("(oas)"), + G_CALLBACK (object_manager_interfaces_removed), self); } static void @@ -287,24 +275,19 @@ bluez_connect (NMBluez5Manager *self) } static void -name_owner_changed_cb (NMDBusManager *dbus_mgr, - const char *name, - const char *old_owner, - const char *new_owner, +name_owner_changed_cb (GObject *object, + GParamSpec *pspec, gpointer user_data) { NMBluez5Manager *self = NM_BLUEZ5_MANAGER (user_data); NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); - gboolean old_owner_good = (old_owner && strlen (old_owner)); - gboolean new_owner_good = (new_owner && strlen (new_owner)); + char *owner; - /* Can't handle the signal if its not from the Bluez */ - if (strcmp (BLUEZ_SERVICE, name)) - return; - - if (old_owner_good && !new_owner_good) { - if (priv->devices) + if (priv->devices) { + owner = g_dbus_proxy_get_name_owner (priv->proxy); + if (!owner) remove_all_devices (self); + g_free (owner); } } @@ -314,8 +297,8 @@ bluez_cleanup (NMBluez5Manager *self, gboolean do_signal) NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); if (priv->proxy) { - g_object_unref (priv->proxy); - priv->proxy = NULL; + g_signal_handlers_disconnect_by_func (priv->proxy, G_CALLBACK (name_owner_changed_cb), self); + g_clear_object (&priv->proxy); } if (do_signal) @@ -324,19 +307,6 @@ bluez_cleanup (NMBluez5Manager *self, gboolean do_signal) g_hash_table_remove_all (priv->devices); } -static void -dbus_connection_changed_cb (NMDBusManager *dbus_mgr, - DBusGConnection *connection, - gpointer user_data) -{ - NMBluez5Manager *self = NM_BLUEZ5_MANAGER (user_data); - - if (!connection) - bluez_cleanup (self, TRUE); - else - bluez_connect (self); -} - /****************************************************************/ NMBluez5Manager * @@ -354,19 +324,6 @@ nm_bluez5_manager_init (NMBluez5Manager *self) { NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); - priv->dbus_mgr = nm_dbus_manager_get (); - g_assert (priv->dbus_mgr); - - g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_NAME_OWNER_CHANGED, - G_CALLBACK (name_owner_changed_cb), - self); - - g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED, - G_CALLBACK (dbus_connection_changed_cb), - self); - bluez_connect (self); priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, @@ -377,16 +334,9 @@ static void dispose (GObject *object) { NMBluez5Manager *self = NM_BLUEZ5_MANAGER (object); - NMBluez5ManagerPrivate *priv = NM_BLUEZ5_MANAGER_GET_PRIVATE (self); bluez_cleanup (self, FALSE); - if (priv->dbus_mgr) { - g_signal_handlers_disconnect_by_func (priv->dbus_mgr, name_owner_changed_cb, self); - g_signal_handlers_disconnect_by_func (priv->dbus_mgr, dbus_connection_changed_cb, self); - priv->dbus_mgr = NULL; - } - G_OBJECT_CLASS (nm_bluez5_manager_parent_class)->dispose (object); } diff --git a/src/devices/bluetooth/nm-bluez5-manager.h b/src/devices/bluetooth/nm-bluez5-manager.h index 8152976d..ae5512f8 100644 --- a/src/devices/bluetooth/nm-bluez5-manager.h +++ b/src/devices/bluetooth/nm-bluez5-manager.h @@ -22,11 +22,8 @@ #ifndef __NETWORKMANAGER_BLUEZ5_MANAGER_H__ #define __NETWORKMANAGER_BLUEZ5_MANAGER_H__ -#include -#include - -#include -#include "nm-connection-provider.h" +#include "nm-default.h" +#include "nm-connection-provider.h" G_BEGIN_DECLS diff --git a/src/devices/bluetooth/nm-bt-enum-types.c b/src/devices/bluetooth/nm-bt-enum-types.c index 16741c9f..207055e1 100644 --- a/src/devices/bluetooth/nm-bt-enum-types.c +++ b/src/devices/bluetooth/nm-bt-enum-types.c @@ -3,6 +3,8 @@ /* Generated by glib-mkenums. Do not edit */ +#include "config.h" + #include "nm-bt-enum-types.h" #include "nm-bt-error.h" diff --git a/src/devices/bluetooth/nm-bt-error.c b/src/devices/bluetooth/nm-bt-error.c index e3b8e7f5..9c35d8b6 100644 --- a/src/devices/bluetooth/nm-bt-error.c +++ b/src/devices/bluetooth/nm-bt-error.c @@ -20,7 +20,7 @@ #include "config.h" -#include +#include "nm-default.h" #include "nm-bt-error.h" GQuark diff --git a/src/devices/bluetooth/nm-device-bt-glue.h b/src/devices/bluetooth/nm-device-bt-glue.h deleted file mode 100644 index b6f851b2..00000000 --- a/src/devices/bluetooth/nm-device-bt-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_bt_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_bt_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_bt_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_bt_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_bt_object_info = { 1, - dbus_glib_nm_device_bt_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.Bluetooth\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.Bluetooth\0HwAddress\0hw_address\0read\0org.freedesktop.NetworkManager.Device.Bluetooth\0Name\0name\0read\0org.freedesktop.NetworkManager.Device.Bluetooth\0BtCapabilities\0bt_capabilities\0read\0\0" -}; - diff --git a/src/devices/bluetooth/nm-device-bt.c b/src/devices/bluetooth/nm-device-bt.c index 88033e2e..1e3f9cdc 100644 --- a/src/devices/bluetooth/nm-device-bt.c +++ b/src/devices/bluetooth/nm-device-bt.c @@ -23,16 +23,11 @@ #include #include -#include -#include - -#include "nm-glib-compat.h" +#include "nm-default.h" #include "nm-bluez-common.h" #include "nm-bluez-device.h" -#include "nm-dbus-manager.h" #include "nm-device-bt.h" #include "nm-device-private.h" -#include "nm-logging.h" #include "ppp-manager/nm-ppp-manager.h" #include "nm-setting-connection.h" #include "nm-setting-bluetooth.h" @@ -40,14 +35,17 @@ #include "nm-setting-gsm.h" #include "nm-setting-serial.h" #include "nm-setting-ppp.h" -#include "nm-device-bt-glue.h" #include "NetworkManagerUtils.h" #include "nm-bt-enum-types.h" #include "nm-utils.h" #include "nm-bt-error.h" #include "nm-bt-enum-types.h" -#define MM_DBUS_SERVICE "org.freedesktop.ModemManager1" +#include "nmdbus-device-bt.h" + +#define MM_DBUS_SERVICE "org.freedesktop.ModemManager1" +#define MM_DBUS_PATH "/org/freedesktop/ModemManager1" +#define MM_DBUS_INTERFACE "org.freedesktop.ModemManager1" #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceBt); @@ -59,8 +57,7 @@ G_DEFINE_TYPE (NMDeviceBt, nm_device_bt, NM_TYPE_DEVICE) static gboolean modem_stage1 (NMDeviceBt *self, NMModem *modem, NMDeviceStateReason *reason); typedef struct { - NMDBusManager *dbus_mgr; - guint mm_watch_id; + GDBusProxy *mm_proxy; gboolean mm_running; NMBluezDevice *bt_device; @@ -461,7 +458,7 @@ modem_prepare_result (NMModem *modem, * the device to be auto-activated anymore, which would risk locking * the SIM if the incorrect PIN continues to be used. */ - g_object_set (G_OBJECT (device), NM_DEVICE_AUTOCONNECT, FALSE, NULL); + nm_device_set_autoconnect (device, FALSE); _LOGI (LOGD_MB, "disabling autoconnect due to failed SIM PIN"); } @@ -635,10 +632,7 @@ component_added (NMDevice *device, GObject *component) g_free (base); /* Got the modem */ - if (priv->timeout_id) { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } + nm_clear_g_source (&priv->timeout_id); /* Can only accept the modem in stage2, but since the interface matched * what we were expecting, don't let anything else claim the modem either. @@ -706,10 +700,7 @@ check_connect_continue (NMDeviceBt *self) dun ? "DUN" : (pan ? "PAN" : "unknown")); /* Kill the connect timeout since we're connected now */ - if (priv->timeout_id) { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } + nm_clear_g_source (&priv->timeout_id); if (pan) { /* Bluez says we're connected now. Start IP config. */ @@ -824,7 +815,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (device); NMConnection *connection; - connection = nm_device_get_connection (device); + connection = nm_device_get_applied_connection (device); g_assert (connection); priv->bt_type = get_connection_bt_type (connection); if (priv->bt_type == NM_BT_CAPABILITY_NONE) { @@ -914,10 +905,7 @@ deactivate (NMDevice *device) if (priv->bt_type != NM_BT_CAPABILITY_NONE) nm_bluez_device_disconnect (priv->bt_device); - if (priv->timeout_id) { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } + nm_clear_g_source (&priv->timeout_id); priv->bt_type = NM_BT_CAPABILITY_NONE; @@ -967,25 +955,17 @@ set_mm_running (NMDeviceBt *self, gboolean running) } static void -mm_name_owner_changed (NMDBusManager *dbus_mgr, - const char *name, - const char *old_owner, - const char *new_owner, +mm_name_owner_changed (GObject *object, + GParamSpec *pspec, NMDeviceBt *self) { - gboolean old_owner_good; - gboolean new_owner_good; - - /* Can't handle the signal if its not from the modem service */ - if (strcmp (MM_DBUS_SERVICE, name) != 0) - return; - - old_owner_good = (old_owner && strlen (old_owner)); - new_owner_good = (new_owner && strlen (new_owner)); + char *owner; - if (!old_owner_good && new_owner_good) + owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object)); + if (owner) { set_mm_running (self, TRUE); - else if (old_owner_good && !new_owner_good) + g_free (owner); + } else set_mm_running (self, FALSE); } @@ -1021,18 +1001,27 @@ static void nm_device_bt_init (NMDeviceBt *self) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self); - gboolean mm_running; - - priv->dbus_mgr = nm_dbus_manager_get (); - - priv->mm_watch_id = g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_NAME_OWNER_CHANGED, - G_CALLBACK (mm_name_owner_changed), - self); + GError *error = NULL; - /* Initial check to see if ModemManager is running */ - mm_running = nm_dbus_manager_name_has_owner (priv->dbus_mgr, MM_DBUS_SERVICE); - set_mm_running (self, mm_running); + priv->mm_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, + NULL, + MM_DBUS_SERVICE, + MM_DBUS_PATH, + MM_DBUS_INTERFACE, + NULL, &error); + if (priv->mm_proxy) { + g_signal_connect (priv->mm_proxy, "notify::g-name-owner", + G_CALLBACK (mm_name_owner_changed), + self); + mm_name_owner_changed (G_OBJECT (priv->mm_proxy), NULL, self); + } else { + _LOGW (LOGD_MB, "Could not create proxy for '%s': %s", + MM_DBUS_SERVICE, error->message); + g_clear_error (&error); + } } static void @@ -1106,18 +1095,14 @@ dispose (GObject *object) { NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (object); - if (priv->timeout_id) { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } + nm_clear_g_source (&priv->timeout_id); g_signal_handlers_disconnect_matched (priv->bt_device, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object); - if (priv->dbus_mgr && priv->mm_watch_id) { - g_signal_handler_disconnect (priv->dbus_mgr, priv->mm_watch_id); - priv->mm_watch_id = 0; + if (priv->mm_proxy) { + g_signal_handlers_disconnect_by_func (priv->mm_proxy, G_CALLBACK (mm_name_owner_changed), object); + g_clear_object (&priv->mm_proxy); } - priv->dbus_mgr = NULL; modem_cleanup (NM_DEVICE_BT (object)); g_clear_object (&priv->bt_device); @@ -1197,7 +1182,7 @@ nm_device_bt_class_init (NMDeviceBtClass *klass) G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_bt_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_BLUETOOTH_SKELETON, + NULL); } diff --git a/src/devices/bluetooth/nm-device-bt.h b/src/devices/bluetooth/nm-device-bt.h index c1e95d91..c565745f 100644 --- a/src/devices/bluetooth/nm-device-bt.h +++ b/src/devices/bluetooth/nm-device-bt.h @@ -21,7 +21,7 @@ #ifndef __NETWORKMANAGER_DEVICE_BT_H__ #define __NETWORKMANAGER_DEVICE_BT_H__ -#include +#include "nm-device.h" #include "nm-bluez-device.h" #include "nm-modem.h" diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index afcba3b3..dfd1de6d 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -20,26 +20,20 @@ #include "config.h" -#include -#include - #include #include -#include "gsystem-local-alloc.h" +#include "nm-default.h" #include "nm-device-bond.h" -#include "nm-logging.h" #include "NetworkManagerUtils.h" #include "nm-device-private.h" #include "nm-platform.h" -#include "nm-dbus-glib-types.h" -#include "nm-dbus-manager.h" #include "nm-enum-types.h" #include "nm-device-factory.h" #include "nm-core-internal.h" #include "nm-ip4-config.h" -#include "nm-device-bond-glue.h" +#include "nmdbus-device-bond.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceBond); @@ -52,13 +46,6 @@ typedef struct { int dummy; } NMDeviceBondPrivate; -enum { - PROP_0, - PROP_SLAVES, - - LAST_PROP -}; - /******************************************************************/ static NMDeviceCapabilities @@ -143,7 +130,7 @@ set_bond_attr (NMDevice *device, const char *attr, const char *value) gboolean ret; int ifindex = nm_device_get_ifindex (device); - ret = nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, attr, value); + ret = nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, attr, value); if (!ret) _LOGW (LOGD_HW, "failed to set bonding attribute '%s' to '%s'", attr, value); return ret; @@ -177,7 +164,7 @@ update_connection (NMDevice *device, NMConnection *connection) /* Read bond options from sysfs and update the Bond setting to match */ options = nm_setting_bond_get_valid_options (s_bond); while (options && *options) { - gs_free char *value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, *options); + gs_free char *value = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, *options); const char *defvalue = nm_setting_bond_get_option_default (s_bond, *options); if (value && !ignore_if_zero (*options, value) && (g_strcmp0 (value, defvalue) != 0)) { @@ -270,7 +257,7 @@ apply_bonding_config (NMDevice *device) * arp_interval doesn't require miimon to be 0 */ - connection = nm_device_get_connection (device); + connection = nm_device_get_applied_connection (device); g_assert (connection); s_bond = nm_connection_get_setting_bond (connection); g_assert (s_bond); @@ -333,7 +320,7 @@ apply_bonding_config (NMDevice *device) } /* Clear ARP targets */ - contents = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, "arp_ip_target"); + contents = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, "arp_ip_target"); set_arp_targets (device, contents, " \n", "-"); g_free (contents); @@ -383,7 +370,7 @@ ip4_config_pre_commit (NMDevice *self, NMIP4Config *config) NMSettingWired *s_wired; guint32 mtu; - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); g_assert (connection); s_wired = nm_connection_get_setting_wired (connection); @@ -421,17 +408,16 @@ enslave_slave (NMDevice *device, } else _LOGI (LOGD_BOND, "bond slave %s was enslaved", slave_iface); - g_object_notify (G_OBJECT (device), NM_DEVICE_BOND_SLAVES); return TRUE; } -static gboolean +static void release_slave (NMDevice *device, NMDevice *slave, gboolean configure) { NMDeviceBond *self = NM_DEVICE_BOND (device); - gboolean success = TRUE, no_firmware = FALSE; + gboolean success, no_firmware = FALSE; if (configure) { success = nm_platform_link_release (NM_PLATFORM_GET, @@ -445,65 +431,48 @@ release_slave (NMDevice *device, _LOGW (LOGD_BOND, "failed to release bond slave %s", nm_device_get_ip_iface (slave)); } - } else { - _LOGI (LOGD_BOND, "bond slave %s was released", - nm_device_get_ip_iface (slave)); - } - - if (success) - g_object_notify (G_OBJECT (device), NM_DEVICE_BOND_SLAVES); - if (configure) { /* Kernel bonding code "closes" the slave when releasing it, (which clears * IFF_UP), so we must bring it back up here to ensure carrier changes and * other state is noticed by the now-released slave. */ if (!nm_device_bring_up (slave, TRUE, &no_firmware)) _LOGW (LOGD_BOND, "released bond slave could not be brought up."); + } else { + _LOGI (LOGD_BOND, "bond slave %s was released", + nm_device_get_ip_iface (slave)); } - - return success; } -/******************************************************************/ - -static void -nm_device_bond_init (NMDeviceBond * self) +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) { -} + const char *iface = nm_device_get_iface (device); + NMPlatformError plerr; -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - GPtrArray *slaves; - GSList *list, *iter; - - switch (prop_id) { - break; - case PROP_SLAVES: - slaves = g_ptr_array_new (); - list = nm_device_master_get_slaves (NM_DEVICE (object)); - for (iter = list; iter; iter = iter->next) - g_ptr_array_add (slaves, g_strdup (nm_device_get_path (NM_DEVICE (iter->data)))); - g_slist_free (list); - g_value_take_boxed (value, slaves); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + g_assert (iface); + + plerr = nm_platform_link_bond_add (NM_PLATFORM_GET, iface, out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create bond interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; } + return TRUE; } +/******************************************************************/ + static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) +nm_device_bond_init (NMDeviceBond * self) { - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } } static void @@ -514,11 +483,7 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) g_type_class_add_private (object_class, sizeof (NMDeviceBondPrivate)); - parent_class->connection_type = NM_SETTING_BOND_SETTING_NAME; - - /* virtual methods */ - object_class->get_property = get_property; - object_class->set_property = set_property; + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_BOND_SETTING_NAME, NM_LINK_TYPE_BOND) parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->is_available = is_available; @@ -529,22 +494,15 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) parent_class->update_connection = update_connection; parent_class->master_update_slave_connection = master_update_slave_connection; + parent_class->create_and_realize = create_and_realize; parent_class->act_stage1_prepare = act_stage1_prepare; parent_class->ip4_config_pre_commit = ip4_config_pre_commit; parent_class->enslave_slave = enslave_slave; parent_class->release_slave = release_slave; - /* properties */ - g_object_class_install_property - (object_class, PROP_SLAVES, - g_param_spec_boxed (NM_DEVICE_BOND_SLAVES, "", "", - DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_bond_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_BOND_SKELETON, + NULL); } /*************************************************************/ @@ -553,45 +511,18 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) #define NM_BOND_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BOND_FACTORY, NMBondFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) -{ - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BOND, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_DRIVER, "bonding", - NM_DEVICE_TYPE_DESC, "Bond", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BOND, - NM_DEVICE_IS_MASTER, TRUE, - NULL); -} - -static NMDevice * -create_virtual_device_for_connection (NMDeviceFactory *factory, - NMConnection *connection, - NMDevice *parent, - GError **error) +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) { - const char *iface = nm_connection_get_interface_name (connection); - NMPlatformError plerr; - const NMPlatformLink *plink; - - g_assert (iface); - - plerr = nm_platform_bond_add (NM_PLATFORM_GET, iface, NULL); - if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { - g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create bond interface '%s' for '%s': %s", - iface, - nm_connection_get_id (connection), - nm_platform_error_to_string (plerr)); - return NULL; - } - plink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, iface); - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BOND, - NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_IFACE, iface, NM_DEVICE_DRIVER, "bonding", NM_DEVICE_TYPE_DESC, "Bond", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BOND, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_BOND, NM_DEVICE_IS_MASTER, TRUE, NULL); } @@ -599,7 +530,6 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NM_DEVICE_FACTORY_DEFINE_INTERNAL (BOND, Bond, bond, NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BOND) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BOND_SETTING_NAME), - factory_iface->new_link = new_link; - factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; + factory_iface->create_device = create_device; ) diff --git a/src/devices/nm-device-bond.h b/src/devices/nm-device-bond.h index 17217a57..9e86719e 100644 --- a/src/devices/nm-device-bond.h +++ b/src/devices/nm-device-bond.h @@ -21,8 +21,6 @@ #ifndef __NETWORKMANAGER_DEVICE_BOND_H__ #define __NETWORKMANAGER_DEVICE_BOND_H__ -#include - #include "nm-device.h" G_BEGIN_DECLS @@ -34,8 +32,6 @@ G_BEGIN_DECLS #define NM_IS_DEVICE_BOND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_BOND)) #define NM_DEVICE_BOND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_BOND, NMDeviceBondClass)) -#define NM_DEVICE_BOND_SLAVES "slaves" - typedef NMDevice NMDeviceBond; typedef NMDeviceClass NMDeviceBondClass; diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index d6435530..843c5be4 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -15,29 +15,23 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2011 - 2012 Red Hat, Inc. + * Copyright 2011 - 2015 Red Hat, Inc. */ #include "config.h" -#include -#include - #include -#include "gsystem-local-alloc.h" +#include "nm-default.h" #include "nm-device-bridge.h" -#include "nm-logging.h" #include "NetworkManagerUtils.h" #include "nm-device-private.h" -#include "nm-dbus-glib-types.h" -#include "nm-dbus-manager.h" #include "nm-enum-types.h" #include "nm-platform.h" #include "nm-device-factory.h" #include "nm-core-internal.h" -#include "nm-device-bridge-glue.h" +#include "nmdbus-device-bridge.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceBridge); @@ -50,13 +44,6 @@ typedef struct { int dummy; } NMDeviceBridgePrivate; -enum { - PROP_0, - PROP_SLAVES, - - LAST_PROP -}; - /******************************************************************/ static NMDeviceCapabilities @@ -103,7 +90,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) return FALSE; mac_address = nm_setting_bridge_get_mac_address (s_bridge); - if (mac_address) { + if (mac_address && nm_device_is_real (device)) { const char *hw_addr; hw_addr = nm_device_get_hw_address (device); @@ -156,6 +143,7 @@ static const Option master_options[] = { { NM_SETTING_BRIDGE_HELLO_TIME, "hello_time", TRUE, TRUE }, { NM_SETTING_BRIDGE_MAX_AGE, "max_age", TRUE, TRUE }, { NM_SETTING_BRIDGE_AGEING_TIME, "ageing_time", TRUE, TRUE }, + { NM_SETTING_BRIDGE_MULTICAST_SNOOPING, "multicast_snooping", FALSE, FALSE }, { NULL, NULL } }; @@ -211,9 +199,9 @@ commit_option (NMDevice *device, NMSetting *setting, const Option *option, gbool value = g_strdup_printf ("%u", uval); if (slave) - nm_platform_slave_set_option (NM_PLATFORM_GET, ifindex, option->sysname, value); + nm_platform_sysctl_slave_set_option (NM_PLATFORM_GET, ifindex, option->sysname, value); else - nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, option->sysname, value); + nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, option->sysname, value); } static void @@ -257,7 +245,7 @@ update_connection (NMDevice *device, NMConnection *connection) } for (option = master_options; option->name; option++) { - gs_free char *str = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, option->sysname); + gs_free char *str = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, option->sysname); int value; if (str) { @@ -296,7 +284,7 @@ master_update_slave_connection (NMDevice *device, } for (option = slave_options; option->name; option++) { - gs_free char *str = nm_platform_slave_get_option (NM_PLATFORM_GET, ifindex_slave, option->sysname); + gs_free char *str = nm_platform_sysctl_slave_get_option (NM_PLATFORM_GET, ifindex_slave, option->sysname); int value; if (str) { @@ -322,7 +310,7 @@ static NMActStageReturn act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) { NMActStageReturn ret; - NMConnection *connection = nm_device_get_connection (device); + NMConnection *connection = nm_device_get_applied_connection (device); g_assert (connection); @@ -356,18 +344,16 @@ enslave_slave (NMDevice *device, nm_device_get_ip_iface (slave)); } - g_object_notify (G_OBJECT (device), NM_DEVICE_BRIDGE_SLAVES); - return TRUE; } -static gboolean +static void release_slave (NMDevice *device, NMDevice *slave, gboolean configure) { NMDeviceBridge *self = NM_DEVICE_BRIDGE (device); - gboolean success = TRUE; + gboolean success; if (configure) { success = nm_platform_link_release (NM_PLATFORM_GET, @@ -385,49 +371,57 @@ release_slave (NMDevice *device, _LOGI (LOGD_BRIDGE, "bridge port %s was detached", nm_device_get_ip_iface (slave)); } - - g_object_notify (G_OBJECT (device), NM_DEVICE_BRIDGE_SLAVES); - return success; } -/******************************************************************/ - -static void -nm_device_bridge_init (NMDeviceBridge * self) +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) { -} + NMSettingBridge *s_bridge; + const char *iface = nm_device_get_iface (device); + const char *hwaddr; + guint8 mac_address[NM_UTILS_HWADDR_LEN_MAX]; + NMPlatformError plerr; -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - GPtrArray *slaves; - GSList *list, *iter; - - switch (prop_id) { - case PROP_SLAVES: - slaves = g_ptr_array_new (); - list = nm_device_master_get_slaves (NM_DEVICE (object)); - for (iter = list; iter; iter = iter->next) - g_ptr_array_add (slaves, g_strdup (nm_device_get_path (NM_DEVICE (iter->data)))); - g_slist_free (list); - g_value_take_boxed (value, slaves); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + g_assert (iface); + + s_bridge = nm_connection_get_setting_bridge (connection); + g_assert (s_bridge); + hwaddr = nm_setting_bridge_get_mac_address (s_bridge); + if (hwaddr) { + if (!nm_utils_hwaddr_aton (hwaddr, mac_address, ETH_ALEN)) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "Invalid hardware address '%s'", + hwaddr); + return FALSE; + } + } + + plerr = nm_platform_link_bridge_add (NM_PLATFORM_GET, + iface, + hwaddr ? mac_address : NULL, + hwaddr ? ETH_ALEN : 0, + out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create bridge interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; } + + return TRUE; } +/******************************************************************/ + static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) +nm_device_bridge_init (NMDeviceBridge * self) { - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } } static void @@ -438,11 +432,7 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass) g_type_class_add_private (object_class, sizeof (NMDeviceBridgePrivate)); - parent_class->connection_type = NM_SETTING_BRIDGE_SETTING_NAME; - - /* virtual methods */ - object_class->get_property = get_property; - object_class->set_property = set_property; + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_BRIDGE_SETTING_NAME, NM_LINK_TYPE_BRIDGE) parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->is_available = is_available; @@ -453,21 +443,14 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass) parent_class->update_connection = update_connection; parent_class->master_update_slave_connection = master_update_slave_connection; + parent_class->create_and_realize = create_and_realize; parent_class->act_stage1_prepare = act_stage1_prepare; parent_class->enslave_slave = enslave_slave; parent_class->release_slave = release_slave; - /* properties */ - g_object_class_install_property - (object_class, PROP_SLAVES, - g_param_spec_boxed (NM_DEVICE_BRIDGE_SLAVES, "", "", - DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_bridge_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_BRIDGE_SKELETON, + NULL); } /*************************************************************/ @@ -476,61 +459,18 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass) #define NM_BRIDGE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BRIDGE_FACTORY, NMBridgeFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) -{ - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BRIDGE, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_DRIVER, "bridge", - NM_DEVICE_TYPE_DESC, "Bridge", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BRIDGE, - NM_DEVICE_IS_MASTER, TRUE, - NULL); -} - -static NMDevice * -create_virtual_device_for_connection (NMDeviceFactory *factory, - NMConnection *connection, - NMDevice *parent, - GError **error) +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) { - const char *iface = nm_connection_get_interface_name (connection); - NMSettingBridge *s_bridge; - const char *mac_address_str; - guint8 mac_address[NM_UTILS_HWADDR_LEN_MAX]; - NMPlatformError plerr; - const NMPlatformLink *plink; - - g_assert (iface); - - s_bridge = nm_connection_get_setting_bridge (connection); - g_assert (s_bridge); - - mac_address_str = nm_setting_bridge_get_mac_address (s_bridge); - if (mac_address_str) { - if (!nm_utils_hwaddr_aton (mac_address_str, mac_address, ETH_ALEN)) - mac_address_str = NULL; - } - - plerr = nm_platform_bridge_add (NM_PLATFORM_GET, - iface, - mac_address_str ? mac_address : NULL, - mac_address_str ? ETH_ALEN : 0, - NULL); - if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { - g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create bridge interface '%s' for '%s': %s", - iface, - nm_connection_get_id (connection), - nm_platform_error_to_string (plerr)); - return NULL; - } - plink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, iface); - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BRIDGE, - NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_IFACE, iface, NM_DEVICE_DRIVER, "bridge", NM_DEVICE_TYPE_DESC, "Bridge", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BRIDGE, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_BRIDGE, NM_DEVICE_IS_MASTER, TRUE, NULL); } @@ -538,7 +478,6 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NM_DEVICE_FACTORY_DEFINE_INTERNAL (BRIDGE, Bridge, bridge, NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BRIDGE) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BRIDGE_SETTING_NAME), - factory_iface->new_link = new_link; - factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; + factory_iface->create_device = create_device; ) diff --git a/src/devices/nm-device-bridge.h b/src/devices/nm-device-bridge.h index c11a2c40..46482675 100644 --- a/src/devices/nm-device-bridge.h +++ b/src/devices/nm-device-bridge.h @@ -21,8 +21,7 @@ #ifndef __NETWORKMANAGER_DEVICE_BRIDGE_H__ #define __NETWORKMANAGER_DEVICE_BRIDGE_H__ -#include - +#include "nm-default.h" #include "nm-device.h" G_BEGIN_DECLS @@ -34,8 +33,6 @@ G_BEGIN_DECLS #define NM_IS_DEVICE_BRIDGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_BRIDGE)) #define NM_DEVICE_BRIDGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_BRIDGE, NMDeviceBridgeClass)) -#define NM_DEVICE_BRIDGE_SLAVES "slaves" - typedef NMDevice NMDeviceBridge; typedef NMDeviceClass NMDeviceBridgeClass; diff --git a/src/devices/nm-device-ethernet-utils.c b/src/devices/nm-device-ethernet-utils.c index 585f6a0e..9165de31 100644 --- a/src/devices/nm-device-ethernet-utils.c +++ b/src/devices/nm-device-ethernet-utils.c @@ -19,10 +19,9 @@ #include "config.h" #include -#include -#include #include +#include "nm-default.h" #include "nm-device-ethernet-utils.h" char * diff --git a/src/devices/nm-device-ethernet-utils.h b/src/devices/nm-device-ethernet-utils.h index 5848f7e6..31d645d8 100644 --- a/src/devices/nm-device-ethernet-utils.h +++ b/src/devices/nm-device-ethernet-utils.h @@ -19,7 +19,7 @@ #ifndef __NETWORKMANAGER_DEVICE_ETHERNET_UTILS_H__ #define __NETWORKMANAGER_DEVICE_ETHERNET_UTILS_H__ -#include +#include "nm-default.h" char *nm_device_ethernet_utils_get_default_wired_name (const GSList *connections); diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 2dda84b3..a2396ec8 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -21,8 +21,6 @@ #include "config.h" -#include -#include #include #include #include @@ -31,7 +29,7 @@ #include -#include "nm-glib-compat.h" +#include "nm-default.h" #include "nm-device-ethernet.h" #include "nm-device-private.h" #include "nm-activation-request.h" @@ -40,9 +38,7 @@ #include "nm-supplicant-interface.h" #include "nm-supplicant-config.h" #include "ppp-manager/nm-ppp-manager.h" -#include "nm-logging.h" #include "nm-enum-types.h" -#include "nm-dbus-manager.h" #include "nm-platform.h" #include "nm-platform-utils.h" #include "nm-dcb.h" @@ -53,9 +49,8 @@ #include "nm-device-factory.h" #include "nm-core-internal.h" #include "NetworkManagerUtils.h" -#include "gsystem-local-alloc.h" -#include "nm-device-ethernet-glue.h" +#include "nmdbus-device-ethernet.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceEthernet); @@ -76,8 +71,8 @@ typedef struct Supplicant { NMSupplicantInterface *iface; /* signal handler ids */ - guint iface_error_id; - guint iface_state_id; + gulong iface_error_id; + gulong iface_state_id; /* Timeouts and idles */ guint iface_con_error_cb_id; @@ -109,6 +104,7 @@ typedef struct { char * subchan2; char * subchan3; char * subchannels; /* Composite used for checking unmanaged specs */ + char ** subchannels_dbus; /* Array exported on D-Bus */ char * s390_nettype; GHashTable * s390_options; @@ -121,13 +117,14 @@ typedef struct { /* DCB */ DcbWait dcb_wait; guint dcb_timeout_id; - guint dcb_carrier_id; + gulong dcb_carrier_id; } NMDeviceEthernetPrivate; enum { PROP_0, PROP_PERM_HW_ADDRESS, PROP_SPEED, + PROP_S390_SUBCHANNELS, LAST_PROP }; @@ -230,6 +227,12 @@ _update_s390_subchannels (NMDeviceEthernet *self) } else priv->subchannels = g_strdup (priv->subchan1); + priv->subchannels_dbus = g_new (char *, 3 + 1); + priv->subchannels_dbus[0] = g_strdup (priv->subchan1); + priv->subchannels_dbus[1] = g_strdup (priv->subchan2); + priv->subchannels_dbus[2] = g_strdup (priv->subchan3); + priv->subchannels_dbus[3] = NULL; + driver = nm_device_get_driver (NM_DEVICE (self)); _LOGI (LOGD_DEVICE | LOGD_HW, "found s390 '%s' subchannels [%s]", driver ? driver : "(unknown driver)", priv->subchannels); @@ -276,7 +279,7 @@ clear_secrets_tries (NMDevice *device) req = nm_device_get_act_request (device); if (req) { - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); /* Clear wired secrets tries on success, failure, or when deactivating */ g_object_set_data (G_OBJECT (connection), WIRED_SECRETS_TRIES, NULL); } @@ -301,6 +304,14 @@ nm_device_ethernet_init (NMDeviceEthernet *self) priv->s390_options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); } +static void +realize_start_notify (NMDevice *device, const NMPlatformLink *plink) +{ + NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->realize_start_notify (device, plink); + + g_object_notify (G_OBJECT (device), NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS); +} + static NMDeviceCapabilities get_generic_capabilities (NMDevice *device) { @@ -315,21 +326,39 @@ get_generic_capabilities (NMDevice *device) } } +static guint32 +_subchannels_count_num (const char * const *array) +{ + int i; + + if (!array) + return 0; + for (i = 0; array[i]; i++) + /* NOP */; + return i; +} + static gboolean match_subchans (NMDeviceEthernet *self, NMSettingWired *s_wired, gboolean *try_mac) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); const char * const *subchans; + guint32 num1, num2; int i; *try_mac = TRUE; subchans = nm_setting_wired_get_s390_subchannels (s_wired); - if (!subchans) + num1 = _subchannels_count_num (subchans); + num2 = _subchannels_count_num ((const char * const *) priv->subchannels_dbus); + /* connection has no subchannels */ + if (num1 == 0) return TRUE; - /* connection requires subchannels but the device has none */ - if (!priv->subchannels) + if (num2 == 0) + return FALSE; + /* number of subchannels differ */ + if (num1 != num2) return FALSE; /* Make sure each subchannel in the connection is a subchannel of this device */ @@ -412,7 +441,7 @@ device_get_setting (NMDevice *device, GType setting_type) if (req) { NMConnection *connection; - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); if (connection) setting = nm_connection_get_setting (connection, setting_type); } @@ -428,15 +457,8 @@ remove_supplicant_timeouts (NMDeviceEthernet *self) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - if (priv->supplicant.con_timeout_id) { - g_source_remove (priv->supplicant.con_timeout_id); - priv->supplicant.con_timeout_id = 0; - } - - if (priv->supplicant_timeout_id) { - g_source_remove (priv->supplicant_timeout_id); - priv->supplicant_timeout_id = 0; - } + nm_clear_g_source (&priv->supplicant.con_timeout_id); + nm_clear_g_source (&priv->supplicant_timeout_id); } static void @@ -477,17 +499,19 @@ supplicant_interface_release (NMDeviceEthernet *self) static void wired_secrets_cb (NMActRequest *req, - guint32 call_id, - NMConnection *connection, + NMActRequestGetSecretsCallId call_id, + NMSettingsConnection *connection, GError *error, gpointer user_data) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (user_data); NMDevice *dev = NM_DEVICE (self); - g_return_if_fail (req == nm_device_get_act_request (dev)); + if (req != nm_device_get_act_request (dev)) + return; + g_return_if_fail (nm_device_get_state (dev) == NM_DEVICE_STATE_NEED_AUTH); - g_return_if_fail (nm_act_request_get_connection (req) == connection); + g_return_if_fail (nm_act_request_get_settings_connection (req) == connection); if (error) { _LOGW (LOGD_ETHER, "%s", error->message); @@ -505,7 +529,7 @@ link_timeout_cb (gpointer user_data) NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMDevice *dev = NM_DEVICE (self); NMActRequest *req; - NMConnection *connection; + NMConnection *applied_connection; const char *setting_name; priv->supplicant_timeout_id = 0; @@ -526,9 +550,10 @@ link_timeout_cb (gpointer user_data) if (nm_device_get_state (dev) != NM_DEVICE_STATE_CONFIG) goto time_out; - connection = nm_act_request_get_connection (req); - nm_connection_clear_secrets (connection); - setting_name = nm_connection_need_secrets (connection, NULL); + nm_active_connection_clear_secrets (NM_ACTIVE_CONNECTION (req)); + + applied_connection = nm_act_request_get_applied_connection (req); + setting_name = nm_connection_need_secrets (applied_connection, NULL); if (!setting_name) goto time_out; @@ -554,7 +579,8 @@ time_out: } static NMSupplicantConfig * -build_supplicant_config (NMDeviceEthernet *self) +build_supplicant_config (NMDeviceEthernet *self, + GError **error) { const char *con_uuid; NMSupplicantConfig *config = NULL; @@ -562,7 +588,7 @@ build_supplicant_config (NMDeviceEthernet *self) NMConnection *connection; guint32 mtu; - connection = nm_device_get_connection (NM_DEVICE (self)); + connection = nm_device_get_applied_connection (NM_DEVICE (self)); g_assert (connection); con_uuid = nm_connection_get_uuid (connection); mtu = nm_platform_link_get_mtu (NM_PLATFORM_GET, @@ -571,10 +597,9 @@ build_supplicant_config (NMDeviceEthernet *self) config = nm_supplicant_config_new (); security = nm_connection_get_setting_802_1x (connection); - if (!nm_supplicant_config_add_setting_8021x (config, security, con_uuid, mtu, TRUE)) { - _LOGW (LOGD_DEVICE, "Couldn't add 802.1X security setting to supplicant config."); - g_object_unref (config); - config = NULL; + if (!nm_supplicant_config_add_setting_8021x (config, security, con_uuid, mtu, TRUE, error)) { + g_prefix_error (error, "802-1x-setting: "); + g_clear_object (&config); } return config; @@ -593,6 +618,7 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, NMSupplicantConfig *config; gboolean success = FALSE; NMDeviceState devstate; + GError *error = NULL; if (new_state == old_state) return; @@ -605,18 +631,22 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, switch (new_state) { case NM_SUPPLICANT_INTERFACE_STATE_READY: - config = build_supplicant_config (self); + config = build_supplicant_config (self, &error); if (config) { - success = nm_supplicant_interface_set_config (priv->supplicant.iface, config); + success = nm_supplicant_interface_set_config (priv->supplicant.iface, config, &error); g_object_unref (config); if (!success) { _LOGE (LOGD_DEVICE | LOGD_ETHER, - "Activation: (ethernet) couldn't send security configuration to the supplicant."); + "Activation: (ethernet) couldn't send security configuration to the supplicant: %s", + error ? error->message : ""); + g_clear_error (&error); } } else { - _LOGW (LOGD_DEVICE | LOGD_ETHER, - "Activation: (ethernet) couldn't build security configuration."); + _LOGE (LOGD_DEVICE | LOGD_ETHER, + "Activation: (ethernet) couldn't build security configuration: %s", + error ? error->message : ""); + g_clear_error (&error); } if (!success) { @@ -701,19 +731,19 @@ handle_auth_or_fail (NMDeviceEthernet *self, { const char *setting_name; guint32 tries; - NMConnection *connection; + NMConnection *applied_connection; - connection = nm_act_request_get_connection (req); - g_assert (connection); + applied_connection = nm_act_request_get_applied_connection (req); - tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (connection), WIRED_SECRETS_TRIES)); + tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (applied_connection), WIRED_SECRETS_TRIES)); if (tries > 3) return NM_ACT_STAGE_RETURN_FAILURE; nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); - nm_connection_clear_secrets (connection); - setting_name = nm_connection_need_secrets (connection, NULL); + nm_active_connection_clear_secrets (NM_ACTIVE_CONNECTION (req)); + + setting_name = nm_connection_need_secrets (applied_connection, NULL); if (setting_name) { NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; @@ -721,7 +751,7 @@ handle_auth_or_fail (NMDeviceEthernet *self, flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; nm_act_request_get_secrets (req, setting_name, flags, NULL, wired_secrets_cb, self); - g_object_set_data (G_OBJECT (connection), WIRED_SECRETS_TRIES, GUINT_TO_POINTER (++tries)); + g_object_set_data (G_OBJECT (applied_connection), WIRED_SECRETS_TRIES, GUINT_TO_POINTER (++tries)); } else _LOGI (LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); @@ -751,7 +781,7 @@ supplicant_connection_timeout_cb (gpointer user_data) req = nm_device_get_act_request (device); g_assert (req); - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); g_assert (connection); /* Ask for new secrets only if we've never activated this connection @@ -873,7 +903,7 @@ nm_8021x_stage2_config (NMDeviceEthernet *self, NMDeviceStateReason *reason) const char *setting_name; NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; - connection = nm_device_get_connection (NM_DEVICE (self)); + connection = nm_device_get_applied_connection (NM_DEVICE (self)); g_assert (connection); security = nm_connection_get_setting_802_1x (connection); if (!security) { @@ -959,7 +989,7 @@ pppoe_stage3_ip4_config_start (NMDeviceEthernet *self, NMDeviceStateReason *reas req = nm_device_get_act_request (NM_DEVICE (self)); g_assert (req); - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); g_assert (req); s_pppoe = nm_connection_get_setting_pppoe (connection); @@ -967,19 +997,18 @@ pppoe_stage3_ip4_config_start (NMDeviceEthernet *self, NMDeviceStateReason *reas priv->ppp_manager = nm_ppp_manager_new (nm_device_get_iface (NM_DEVICE (self))); if (nm_ppp_manager_start (priv->ppp_manager, req, nm_setting_pppoe_get_username (s_pppoe), 30, &err)) { - g_signal_connect (priv->ppp_manager, "state-changed", - G_CALLBACK (ppp_state_changed), - self); + g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_STATE_CHANGED, + G_CALLBACK (ppp_state_changed), + self); g_signal_connect (priv->ppp_manager, "ip4-config", - G_CALLBACK (ppp_ip4_config), - self); + G_CALLBACK (ppp_ip4_config), + self); ret = NM_ACT_STAGE_RETURN_POSTPONE; } else { _LOGW (LOGD_DEVICE, "PPPoE failed to start: %s", err->message); g_error_free (err); - g_object_unref (priv->ppp_manager); - priv->ppp_manager = NULL; + nm_exported_object_clear_and_unexport (&priv->ppp_manager); *reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED; } @@ -994,10 +1023,7 @@ dcb_timeout_cleanup (NMDevice *device) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); - if (priv->dcb_timeout_id) { - g_source_remove (priv->dcb_timeout_id); - priv->dcb_timeout_id = 0; - } + nm_clear_g_source (&priv->dcb_timeout_id); } static void @@ -1005,10 +1031,7 @@ dcb_carrier_cleanup (NMDevice *device) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); - if (priv->dcb_carrier_id) { - g_signal_handler_disconnect (device, priv->dcb_carrier_id); - priv->dcb_carrier_id = 0; - } + nm_clear_g_signal_handler (device, &priv->dcb_carrier_id); } static void dcb_state (NMDevice *device, gboolean timeout); @@ -1280,7 +1303,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) } /* PPPoE setup */ - if (nm_connection_is_type (nm_device_get_connection (device), + if (nm_connection_is_type (nm_device_get_applied_connection (device), NM_SETTING_PPPOE_SETTING_NAME)) { NMSettingPpp *s_ppp; @@ -1335,7 +1358,7 @@ ip4_config_pre_commit (NMDevice *device, NMIP4Config *config) if (NM_DEVICE_ETHERNET_GET_PRIVATE (device)->ppp_manager) return; - connection = nm_device_get_connection (device); + connection = nm_device_get_applied_connection (device); g_assert (connection); s_wired = nm_connection_get_setting_wired (connection); g_assert (s_wired); @@ -1357,20 +1380,14 @@ deactivate (NMDevice *device) /* Clear wired secrets tries when deactivating */ clear_secrets_tries (device); - if (priv->pppoe_wait_id) { - g_source_remove (priv->pppoe_wait_id); - priv->pppoe_wait_id = 0; - } + nm_clear_g_source (&priv->pppoe_wait_id); if (priv->pending_ip4_config) { g_object_unref (priv->pending_ip4_config); priv->pending_ip4_config = NULL; } - if (priv->ppp_manager) { - g_object_unref (priv->ppp_manager); - priv->ppp_manager = NULL; - } + nm_exported_object_clear_and_unexport (&priv->ppp_manager); supplicant_interface_release (self); @@ -1547,16 +1564,8 @@ update_connection (NMDevice *device, NMConnection *connection) /* We don't set the MTU as we don't know whether it was set explicitly */ /* s390 */ - if (priv->subchannels) { - char **subchannels = g_new (char *, 3 + 1); - - subchannels[0] = g_strdup (priv->subchan1); - subchannels[1] = g_strdup (priv->subchan2); - subchannels[2] = g_strdup (priv->subchan3); - subchannels[3] = NULL; - g_object_set (s_wired, NM_SETTING_WIRED_S390_SUBCHANNELS, subchannels, NULL); - g_strfreev (subchannels); - } + if (priv->subchannels_dbus) + g_object_set (s_wired, NM_SETTING_WIRED_S390_SUBCHANNELS, priv->subchannels_dbus, NULL); if (priv->s390_nettype) g_object_set (s_wired, NM_SETTING_WIRED_S390_NETTYPE, priv->s390_nettype, NULL); g_hash_table_iter_init (&iter, priv->s390_options); @@ -1598,10 +1607,44 @@ link_changed (NMDevice *device, NMPlatformLink *info) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); + static const guint8 zero_hwaddr[ETH_ALEN]; + const guint8 *hwaddr; + gsize hwaddrlen = 0; NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->link_changed (device, info); if (!priv->subchan1 && info->initialized) _update_s390_subchannels (self); + + if (!nm_device_get_initial_hw_address (device)) { + hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, + nm_device_get_ifindex (self), + &hwaddrlen); + if (!nm_utils_hwaddr_matches (hwaddr, hwaddrlen, zero_hwaddr, ETH_ALEN)) { + _LOGD (LOGD_DEVICE, "device got a valid hw address"); + nm_device_update_hw_address (self); + nm_device_update_initial_hw_address (self); + if (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE) { + /* + * If the device is UNAVAILABLE, any previous try to + * bring it up probably has failed because of the + * invalid hardware address; try again. + */ + nm_device_bring_up (self, TRUE, NULL); + nm_device_queue_recheck_available (device, + NM_DEVICE_STATE_REASON_NONE, + NM_DEVICE_STATE_REASON_NONE); + } + } + } +} + +static gboolean +is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) +{ + if (!NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->is_available (device, flags)) + return FALSE; + + return !!nm_device_get_initial_hw_address (device); } static void @@ -1610,10 +1653,7 @@ dispose (GObject *object) NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - if (priv->pppoe_wait_id) { - g_source_remove (priv->pppoe_wait_id); - priv->pppoe_wait_id = 0; - } + nm_clear_g_source (&priv->pppoe_wait_id); dcb_timeout_cleanup (NM_DEVICE (self)); dcb_carrier_cleanup (NM_DEVICE (self)); @@ -1632,6 +1672,7 @@ finalize (GObject *object) g_free (priv->subchan2); g_free (priv->subchan3); g_free (priv->subchannels); + g_strfreev (priv->subchannels_dbus); g_free (priv->s390_nettype); g_hash_table_destroy (priv->s390_options); @@ -1652,6 +1693,9 @@ get_property (GObject *object, guint prop_id, case PROP_SPEED: g_value_set_uint (value, priv->speed); break; + case PROP_S390_SUBCHANNELS: + g_value_set_boxed (value, priv->subchannels_dbus); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1677,7 +1721,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) g_type_class_add_private (object_class, sizeof (NMDeviceEthernetPrivate)); - parent_class->connection_type = NM_SETTING_WIRED_SETTING_NAME; + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_WIRED_SETTING_NAME, NM_LINK_TYPE_ETHERNET) /* virtual methods */ object_class->constructor = constructor; @@ -1687,6 +1731,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) object_class->set_property = set_property; parent_class->get_generic_capabilities = get_generic_capabilities; + parent_class->realize_start_notify = realize_start_notify; parent_class->check_connection_compatible = check_connection_compatible; parent_class->complete_connection = complete_connection; parent_class->new_default_connection = new_default_connection; @@ -1700,6 +1745,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) parent_class->update_connection = update_connection; parent_class->carrier_changed = carrier_changed; parent_class->link_changed = link_changed; + parent_class->is_available = is_available; parent_class->state_changed = device_state_changed; @@ -1718,9 +1764,16 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_ethernet_object_info); + g_object_class_install_property + (object_class, PROP_S390_SUBCHANNELS, + g_param_spec_boxed (NM_DEVICE_ETHERNET_S390_SUBCHANNELS, "", "", + G_TYPE_STRV, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_ETHERNET_SKELETON, + NULL); } /*************************************************************/ @@ -1729,18 +1782,23 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) #define NM_ETHERNET_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ETHERNET_FACTORY, NMEthernetFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) { return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ETHERNET, - NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_IFACE, iface, NM_DEVICE_TYPE_DESC, "Ethernet", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_ETHERNET, NULL); } NM_DEVICE_FACTORY_DEFINE_INTERNAL (ETHERNET, Ethernet, ethernet, NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_ETHERNET) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_PPPOE_SETTING_NAME), - factory_iface->new_link = new_link; + factory_iface->create_device = create_device; ) diff --git a/src/devices/nm-device-ethernet.h b/src/devices/nm-device-ethernet.h index ad9ce856..2d284822 100644 --- a/src/devices/nm-device-ethernet.h +++ b/src/devices/nm-device-ethernet.h @@ -22,8 +22,6 @@ #ifndef __NETWORKMANAGER_DEVICE_ETHERNET_H__ #define __NETWORKMANAGER_DEVICE_ETHERNET_H__ -#include - #include "nm-device.h" G_BEGIN_DECLS @@ -37,6 +35,7 @@ G_BEGIN_DECLS #define NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS "perm-hw-address" #define NM_DEVICE_ETHERNET_SPEED "speed" +#define NM_DEVICE_ETHERNET_S390_SUBCHANNELS "s390-subchannels" typedef NMDevice NMDeviceEthernet; typedef NMDeviceClass NMDeviceEthernetClass; diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index 13034808..75731b14 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -27,12 +27,14 @@ #include #include "nm-device-factory.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-platform.h" const NMLinkType _nm_device_factory_no_default_links[] = { NM_LINK_TYPE_NONE }; const char *_nm_device_factory_no_default_settings[] = { NULL }; +G_DEFINE_INTERFACE (NMDeviceFactory, nm_device_factory, G_TYPE_OBJECT) + enum { DEVICE_ADDED, COMPONENT_ADDED, @@ -79,86 +81,64 @@ nm_device_factory_start (NMDeviceFactory *factory) } NMDevice * -nm_device_factory_new_link (NMDeviceFactory *factory, - NMPlatformLink *plink, - gboolean *out_ignore, - GError **error) +nm_device_factory_create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore, + GError **error) { - NMDeviceFactory *interface; + NMDeviceFactoryInterface *interface; const NMLinkType *link_types = NULL; const char **setting_types = NULL; int i; - g_return_val_if_fail (factory != NULL, NULL); - g_return_val_if_fail (plink != NULL, NULL); + g_return_val_if_fail (factory, NULL); + g_return_val_if_fail (iface && *iface, NULL); + g_return_val_if_fail (plink || connection, NULL); + g_return_val_if_fail (!plink || !connection, NULL); - /* Ensure the factory can create interfaces for this connection */ nm_device_factory_get_supported_types (factory, &link_types, &setting_types); - for (i = 0; link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) { - if (plink->type == link_types[i]) - break; - } - if (link_types[i] == NM_LINK_TYPE_UNKNOWN) { - g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, - "Device factory %s does not support link type %s (%d)", - G_OBJECT_TYPE_NAME (factory), - plink->kind, plink->type); - return NULL; - } + if (plink) { + g_return_val_if_fail (strcmp (iface, plink->name) == 0, NULL); - interface = NM_DEVICE_FACTORY_GET_INTERFACE (factory); - if (!interface->new_link) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "Device factory %s cannot manage new devices", - G_OBJECT_TYPE_NAME (factory)); - return NULL; - } - - return interface->new_link (factory, plink, out_ignore, error); -} - -NMDevice * -nm_device_factory_create_virtual_device_for_connection (NMDeviceFactory *factory, - NMConnection *connection, - NMDevice *parent, - GError **error) -{ - NMDeviceFactory *interface; - const char **setting_types = NULL; - gboolean found = FALSE; - int i; + for (i = 0; link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) { + if (plink->type == link_types[i]) + break; + } - g_return_val_if_fail (factory, NULL); - g_return_val_if_fail (connection, NULL); - g_return_val_if_fail (!error || !*error, NULL); - - /* Ensure the factory can create interfaces for this connection */ - nm_device_factory_get_supported_types (factory, NULL, &setting_types); - for (i = 0; setting_types && setting_types[i]; i++) { - if (nm_connection_is_type (connection, setting_types[i])) { - found = TRUE; - break; + if (link_types[i] == NM_LINK_TYPE_UNKNOWN) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Device factory %s does not support link type %s (%d)", + G_OBJECT_TYPE_NAME (factory), + plink->kind, plink->type); + return NULL; + } + } else if (connection) { + for (i = 0; setting_types && setting_types[i]; i++) { + if (nm_connection_is_type (connection, setting_types[i])) + break; } - } - if (!found) { - g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, - "Device factory %s does not support connection type %s", - G_OBJECT_TYPE_NAME (factory), - nm_connection_get_connection_type (connection)); - return NULL; + if (!setting_types[i]) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + "Device factory %s does not support connection type %s", + G_OBJECT_TYPE_NAME (factory), + nm_connection_get_connection_type (connection)); + return NULL; + } } interface = NM_DEVICE_FACTORY_GET_INTERFACE (factory); - if (!interface->create_virtual_device_for_connection) { + if (!interface->create_device) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "Device factory %s cannot create virtual devices", + "Device factory %s cannot manage new devices", G_OBJECT_TYPE_NAME (factory)); return NULL; } - return interface->create_virtual_device_for_connection (factory, connection, parent, error); + return interface->create_device (factory, iface, plink, connection, out_ignore); } const char * @@ -210,7 +190,7 @@ nm_device_factory_get_virtual_iface_name (NMDeviceFactory *factory, /*******************************************************************/ static void -default_init (NMDeviceFactory *factory_iface) +nm_device_factory_default_init (NMDeviceFactoryInterface *factory_iface) { factory_iface->get_virtual_iface_name = get_virtual_iface_name; @@ -218,37 +198,18 @@ default_init (NMDeviceFactory *factory_iface) signals[DEVICE_ADDED] = g_signal_new (NM_DEVICE_FACTORY_DEVICE_ADDED, NM_TYPE_DEVICE_FACTORY, G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMDeviceFactory, device_added), + G_STRUCT_OFFSET (NMDeviceFactoryInterface, device_added), NULL, NULL, NULL, G_TYPE_NONE, 1, NM_TYPE_DEVICE); signals[COMPONENT_ADDED] = g_signal_new (NM_DEVICE_FACTORY_COMPONENT_ADDED, NM_TYPE_DEVICE_FACTORY, G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMDeviceFactory, component_added), + G_STRUCT_OFFSET (NMDeviceFactoryInterface, component_added), g_signal_accumulator_true_handled, NULL, NULL, G_TYPE_BOOLEAN, 1, G_TYPE_OBJECT); } -GType -nm_device_factory_get_type (void) -{ - static volatile gsize g_define_type_id__volatile = 0; - if (g_once_init_enter (&g_define_type_id__volatile)) { - GType g_define_type_id = - g_type_register_static_simple (G_TYPE_INTERFACE, - g_intern_static_string ("NMDeviceFactory"), - sizeof (NMDeviceFactory), - (GClassInitFunc) default_init, - 0, - (GInstanceInitFunc) NULL, - (GTypeFlags) 0); - g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT); - g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); - } - return g_define_type_id__volatile; -} - /*******************************************************************/ static GSList *internal_types = NULL; @@ -325,19 +286,20 @@ nm_device_factory_manager_for_each_factory (NMDeviceFactoryManagerFactoryFunc ca NMDeviceFactory *factory; GSList *list_iter, *list = NULL; - g_return_if_fail (factories_by_link); - g_return_if_fail (factories_by_setting); - - g_hash_table_iter_init (&iter, factories_by_link); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &factory)) { - if (!g_slist_find (list, factory)) - list = g_slist_prepend (list, factory); + if (factories_by_link) { + g_hash_table_iter_init (&iter, factories_by_link); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &factory)) { + if (!g_slist_find (list, factory)) + list = g_slist_prepend (list, factory); + } } - g_hash_table_iter_init (&iter, factories_by_setting); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &factory)) { - if (!g_slist_find (list, factory)) - list = g_slist_prepend (list, factory); + if (factories_by_setting) { + g_hash_table_iter_init (&iter, factories_by_setting); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &factory)) { + if (!g_slist_find (list, factory)) + list = g_slist_prepend (list, factory); + } } for (list_iter = list; list_iter; list_iter = list_iter->next) diff --git a/src/devices/nm-device-factory.h b/src/devices/nm-device-factory.h index 34c056d2..9b7cb35a 100644 --- a/src/devices/nm-device-factory.h +++ b/src/devices/nm-device-factory.h @@ -21,9 +21,6 @@ #ifndef __NETWORKMANAGER_DEVICE_FACTORY_H__ #define __NETWORKMANAGER_DEVICE_FACTORY_H__ -#include -#include - #include "nm-dbus-interface.h" #include "nm-device.h" @@ -56,13 +53,13 @@ typedef NMDeviceFactory * (*NMDeviceFactoryCreateFunc) (GError **error); #define NM_TYPE_DEVICE_FACTORY (nm_device_factory_get_type ()) #define NM_DEVICE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_FACTORY, NMDeviceFactory)) #define NM_IS_DEVICE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_FACTORY)) -#define NM_DEVICE_FACTORY_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_DEVICE_FACTORY, NMDeviceFactory)) +#define NM_DEVICE_FACTORY_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_DEVICE_FACTORY, NMDeviceFactoryInterface)) /* signals */ #define NM_DEVICE_FACTORY_COMPONENT_ADDED "component-added" #define NM_DEVICE_FACTORY_DEVICE_ADDED "device-added" -struct _NMDeviceFactory { +typedef struct { GTypeInterface g_iface; /** @@ -87,51 +84,7 @@ struct _NMDeviceFactory { * Start the factory and discover any existing devices that the factory * can manage. */ - void (*start) (NMDeviceFactory *factory); - - /** - * new_link: - * @factory: the #NMDeviceFactory - * @plink: the new link - * @out_ignore: on return, %TRUE if the link should be ignored - * @error: error if the link could be claimed but an error occurred - * - * The NetworkManager core was notified of a new link which the plugin - * may want to claim and create a #NMDevice subclass for. If the link - * represents a device which the factory does not support, or the link - * is supported but the device could not be created, %NULL should be - * returned and @error should be set. - * - * If the plugin cannot create a #NMDevice for the link and wants the - * core to ignore it, set @out_ignore to %TRUE and return no error. - * - * @plink is guaranteed to be one of the types the factory returns in - * get_supported_types(). - * - * Returns: the #NMDevice if the link was claimed and created, %NULL if not - */ - NMDevice * (*new_link) (NMDeviceFactory *factory, - NMPlatformLink *plink, - gboolean *out_ignore, - GError **error); - - /** - * create_virtual_device_for_connection: - * @factory: the #NMDeviceFactory - * @connection: the #NMConnection - * @error: a @GError in case of failure - * - * Virtual device types (such as team, bond, bridge) may need to be created. - * This function tries to create a device based on the given @connection. - * - * Returns: the newly created #NMDevice. If the factory does not support the - * connection type, it should return %NULL and leave @error unset. On error - * it should set @error and return %NULL. - */ - NMDevice * (*create_virtual_device_for_connection) (NMDeviceFactory *factory, - NMConnection *connection, - NMDevice *parent, - GError **error); + void (*start) (NMDeviceFactory *factory); /** * get_connection_parent: @@ -162,6 +115,30 @@ struct _NMDeviceFactory { NMConnection *connection, const char *parent_iface); + /** + * create_device: + * @factory: the #NMDeviceFactory + * @iface: the interface name of the device + * @plink: the #NMPlatformLink if backed by a kernel device + * @connection: the #NMConnection if not backed by a kernel device + * @out_ignore: on return, %TRUE if the link should be ignored + * + * The plugin should create a new unrealized device using the details given + * by @iface and @plink or @connection. If both @iface and @plink are given, + * they are guaranteed to match. If both @iface and @connection are given, + * @iface is guaranteed to be the interface name that @connection specifies. + * + * If the plugin cannot create a #NMDevice for the link and wants the + * core to ignore it, set @out_ignore to %TRUE and return %NULL. + * + * Returns: the new unrealized #NMDevice, or %NULL + */ + NMDevice * (*create_device) (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore); + /* Signals */ /** @@ -187,7 +164,7 @@ struct _NMDeviceFactory { * Returns: %TRUE if the component was claimed by a device, %FALSE if not */ gboolean (*component_added) (NMDeviceFactory *factory, GObject *component); -}; +} NMDeviceFactoryInterface; GType nm_device_factory_get_type (void); @@ -204,15 +181,12 @@ char * nm_device_factory_get_virtual_iface_name (NMDeviceFactory *factory, void nm_device_factory_start (NMDeviceFactory *factory); -NMDevice * nm_device_factory_new_link (NMDeviceFactory *factory, - NMPlatformLink *plink, - gboolean *out_ignore, - GError **error); - -NMDevice * nm_device_factory_create_virtual_device_for_connection (NMDeviceFactory *factory, - NMConnection *connection, - NMDevice *parent, - GError **error); +NMDevice * nm_device_factory_create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore, + GError **error); /* For use by implementations */ gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory, @@ -249,7 +223,7 @@ extern const char *_nm_device_factory_no_default_settings[]; typedef GObjectClass NM##mixed##FactoryClass; \ \ static GType nm_##lower##_factory_get_type (void); \ - static void device_factory_interface_init (NMDeviceFactory *factory_iface); \ + static void device_factory_interface_init (NMDeviceFactoryInterface *factory_iface); \ \ G_DEFINE_TYPE_EXTENDED (NM##mixed##Factory, nm_##lower##_factory, G_TYPE_OBJECT, 0, \ G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_FACTORY, device_factory_interface_init) \ @@ -262,14 +236,14 @@ extern const char *_nm_device_factory_no_default_settings[]; static void __attribute__((constructor)) \ register_device_factory_internal_##lower (void) \ { \ - g_type_init (); \ + nm_g_type_init (); \ g_type_ensure (NM_TYPE_##upper##_FACTORY); \ } \ \ NM_DEVICE_FACTORY_DECLARE_TYPES(st_code) \ \ static void \ - device_factory_interface_init (NMDeviceFactory *factory_iface) \ + device_factory_interface_init (NMDeviceFactoryInterface *factory_iface) \ { \ factory_iface->get_supported_types = get_supported_types; \ dfi_code \ diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c index 5841d834..2e9c134a 100644 --- a/src/devices/nm-device-generic.c +++ b/src/devices/nm-device-generic.c @@ -24,11 +24,9 @@ #include "nm-device-private.h" #include "nm-enum-types.h" #include "nm-platform.h" -#include "nm-glib-compat.h" -#include "nm-dbus-manager.h" #include "nm-core-internal.h" -#include "nm-device-generic-glue.h" +#include "nmdbus-device-generic.h" G_DEFINE_TYPE (NMDeviceGeneric, nm_device_generic, NM_TYPE_DEVICE) @@ -62,6 +60,21 @@ get_type_description (NMDevice *device) return NM_DEVICE_CLASS (nm_device_generic_parent_class)->get_type_description (device); } +static void +realize_start_notify (NMDevice *device, const NMPlatformLink *plink) +{ + NMDeviceGeneric *self = NM_DEVICE_GENERIC (device); + NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE (self); + int ifindex; + + NM_DEVICE_CLASS (nm_device_generic_parent_class)->realize_start_notify (device, plink); + + g_clear_pointer (&priv->type_description, g_free); + ifindex = nm_device_get_ip_ifindex (NM_DEVICE (self)); + if (ifindex > 0) + priv->type_description = g_strdup (nm_platform_link_get_type_name (NM_PLATFORM_GET, ifindex)); +} + static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection) { @@ -98,12 +111,12 @@ update_connection (NMDevice *device, NMConnection *connection) /**************************************************************/ NMDevice * -nm_device_generic_new (NMPlatformLink *platform_device) +nm_device_generic_new (const NMPlatformLink *plink) { - g_return_val_if_fail (platform_device != NULL, NULL); + g_return_val_if_fail (plink != NULL, NULL); return (NMDevice *) g_object_new (NM_TYPE_DEVICE_GENERIC, - NM_DEVICE_PLATFORM_DEVICE, platform_device, + NM_DEVICE_IFACE, plink->name, NM_DEVICE_TYPE_DESC, "Generic", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, NULL); @@ -112,23 +125,22 @@ nm_device_generic_new (NMPlatformLink *platform_device) static void nm_device_generic_init (NMDeviceGeneric *self) { - nm_device_set_initial_unmanaged_flag (NM_DEVICE (self), NM_UNMANAGED_DEFAULT, TRUE); } -static void -constructed (GObject *object) +static GObject * +constructor (GType type, + guint n_construct_params, + GObjectConstructParam *construct_params) { - NMDeviceGeneric *self = NM_DEVICE_GENERIC (object); - NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE (self); + GObject *object; - if (!priv->type_description) { - int ifindex = nm_device_get_ip_ifindex (NM_DEVICE (self)); + object = G_OBJECT_CLASS (nm_device_generic_parent_class)->constructor (type, + n_construct_params, + construct_params); - if (ifindex != 0) - priv->type_description = g_strdup (nm_platform_link_get_type_name (NM_PLATFORM_GET, ifindex)); - } + nm_device_set_unmanaged_flags_initial (NM_DEVICE (object), NM_UNMANAGED_DEFAULT, TRUE); - G_OBJECT_CLASS (nm_device_generic_parent_class)->constructed (object); + return object; } static void @@ -184,13 +196,14 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass) g_type_class_add_private (klass, sizeof (NMDeviceGenericPrivate)); - parent_class->connection_type = NM_SETTING_GENERIC_SETTING_NAME; + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_GENERIC_SETTING_NAME, NM_LINK_TYPE_ANY) - object_class->constructed = constructed; + object_class->constructor = constructor; object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; + parent_class->realize_start_notify = realize_start_notify; parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->get_type_description = get_type_description; parent_class->check_connection_compatible = check_connection_compatible; @@ -204,7 +217,7 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_generic_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_GENERIC_SKELETON, + NULL); } diff --git a/src/devices/nm-device-generic.h b/src/devices/nm-device-generic.h index c889b1dd..9303a278 100644 --- a/src/devices/nm-device-generic.h +++ b/src/devices/nm-device-generic.h @@ -21,8 +21,6 @@ #ifndef __NETWORKMANAGER_DEVICE_GENERIC_H__ #define __NETWORKMANAGER_DEVICE_GENERIC_H__ -#include - #include "nm-device.h" G_BEGIN_DECLS @@ -47,7 +45,7 @@ typedef struct { GType nm_device_generic_get_type (void); -NMDevice *nm_device_generic_new (NMPlatformLink *platform_device); +NMDevice *nm_device_generic_new (const NMPlatformLink *plink); G_END_DECLS diff --git a/src/devices/nm-device-gre.c b/src/devices/nm-device-gre.c deleted file mode 100644 index b3510d2e..00000000 --- a/src/devices/nm-device-gre.c +++ /dev/null @@ -1,283 +0,0 @@ -/* -*- 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 2013 Red Hat, Inc. - */ - -#include "config.h" - -#include -#include - -#include "nm-device-gre.h" -#include "nm-device-private.h" -#include "nm-dbus-manager.h" -#include "nm-logging.h" -#include "nm-manager.h" -#include "nm-platform.h" -#include "nm-device-factory.h" -#include "nm-core-internal.h" - -#include "nm-device-gre-glue.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceGre); - -G_DEFINE_TYPE (NMDeviceGre, nm_device_gre, NM_TYPE_DEVICE_GENERIC) - -#define NM_DEVICE_GRE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_GRE, NMDeviceGrePrivate)) - -typedef struct { - NMPlatformGreProperties props; -} NMDeviceGrePrivate; - -enum { - PROP_0, - PROP_PARENT, - PROP_INPUT_FLAGS, - PROP_OUTPUT_FLAGS, - PROP_INPUT_KEY, - PROP_OUTPUT_KEY, - PROP_LOCAL, - PROP_REMOTE, - PROP_TTL, - PROP_TOS, - PROP_PATH_MTU_DISCOVERY, - - LAST_PROP -}; - -/**************************************************************/ - -static void -update_properties (NMDevice *device) -{ - NMDeviceGre *self = NM_DEVICE_GRE (device); - NMDeviceGrePrivate *priv = NM_DEVICE_GRE_GET_PRIVATE (self); - GObject *object = G_OBJECT (device); - NMPlatformGreProperties props; - - if (!nm_platform_gre_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) { - _LOGW (LOGD_HW, "could not read gre properties"); - return; - } - - g_object_freeze_notify (object); - - if (priv->props.parent_ifindex != props.parent_ifindex) - g_object_notify (object, NM_DEVICE_GRE_PARENT); - if (priv->props.input_flags != props.input_flags) - g_object_notify (object, NM_DEVICE_GRE_INPUT_FLAGS); - if (priv->props.output_flags != props.output_flags) - g_object_notify (object, NM_DEVICE_GRE_OUTPUT_FLAGS); - if (priv->props.input_key != props.input_key) - g_object_notify (object, NM_DEVICE_GRE_INPUT_KEY); - if (priv->props.output_key != props.output_key) - g_object_notify (object, NM_DEVICE_GRE_OUTPUT_KEY); - if (priv->props.local != props.local) - g_object_notify (object, NM_DEVICE_GRE_LOCAL); - if (priv->props.remote != props.remote) - g_object_notify (object, NM_DEVICE_GRE_REMOTE); - if (priv->props.ttl != props.ttl) - g_object_notify (object, NM_DEVICE_GRE_TTL); - if (priv->props.tos != props.tos) - g_object_notify (object, NM_DEVICE_GRE_TOS); - if (priv->props.path_mtu_discovery != props.path_mtu_discovery) - g_object_notify (object, NM_DEVICE_GRE_PATH_MTU_DISCOVERY); - - memcpy (&priv->props, &props, sizeof (NMPlatformGreProperties)); - - g_object_thaw_notify (object); -} - -static void -link_changed (NMDevice *device, NMPlatformLink *info) -{ - NM_DEVICE_CLASS (nm_device_gre_parent_class)->link_changed (device, info); - update_properties (device); -} - -/**************************************************************/ - -static void -nm_device_gre_init (NMDeviceGre *self) -{ -} - -static void -constructed (GObject *object) -{ - update_properties (NM_DEVICE (object)); - - G_OBJECT_CLASS (nm_device_gre_parent_class)->constructed (object); -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMDeviceGrePrivate *priv = NM_DEVICE_GRE_GET_PRIVATE (object); - char buf[INET_ADDRSTRLEN]; - NMDevice *parent; - - switch (prop_id) { - case PROP_PARENT: - parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->props.parent_ifindex); - g_value_set_boxed (value, parent ? nm_device_get_path (parent) : "/"); - break; - case PROP_INPUT_FLAGS: - g_value_set_uint (value, priv->props.input_flags); - break; - case PROP_OUTPUT_FLAGS: - g_value_set_uint (value, priv->props.output_flags); - break; - case PROP_INPUT_KEY: - g_value_set_uint (value, priv->props.input_key); - break; - case PROP_OUTPUT_KEY: - g_value_set_uint (value, priv->props.output_key); - break; - case PROP_LOCAL: - g_value_set_string (value, inet_ntop (AF_INET, &priv->props.local, buf, sizeof (buf))); - break; - case PROP_REMOTE: - g_value_set_string (value, inet_ntop (AF_INET, &priv->props.remote, buf, sizeof (buf))); - break; - case PROP_TTL: - g_value_set_uchar (value, priv->props.ttl); - break; - case PROP_TOS: - g_value_set_uchar (value, priv->props.tos); - break; - case PROP_PATH_MTU_DISCOVERY: - g_value_set_boolean (value, priv->props.path_mtu_discovery); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -nm_device_gre_class_init (NMDeviceGreClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - - g_type_class_add_private (klass, sizeof (NMDeviceGrePrivate)); - - object_class->constructed = constructed; - object_class->get_property = get_property; - - device_class->link_changed = link_changed; - - /* properties */ - g_object_class_install_property - (object_class, PROP_PARENT, - g_param_spec_boxed (NM_DEVICE_GRE_PARENT, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_INPUT_FLAGS, - g_param_spec_uint (NM_DEVICE_GRE_INPUT_FLAGS, "", "", - 0, G_MAXUINT16, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_OUTPUT_FLAGS, - g_param_spec_uint (NM_DEVICE_GRE_OUTPUT_FLAGS, "", "", - 0, G_MAXUINT16, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_INPUT_KEY, - g_param_spec_uint (NM_DEVICE_GRE_INPUT_KEY, "", "", - 0, G_MAXUINT32, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_OUTPUT_KEY, - g_param_spec_uint (NM_DEVICE_GRE_OUTPUT_KEY, "", "", - 0, G_MAXUINT32, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_LOCAL, - g_param_spec_string (NM_DEVICE_GRE_LOCAL, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_REMOTE, - g_param_spec_string (NM_DEVICE_GRE_REMOTE, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_TTL, - g_param_spec_uchar (NM_DEVICE_GRE_TTL, "", "", - 0, 255, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_TOS, - g_param_spec_uchar (NM_DEVICE_GRE_TOS, "", "", - 0, 255, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_PATH_MTU_DISCOVERY, - g_param_spec_boolean (NM_DEVICE_GRE_PATH_MTU_DISCOVERY, "", "", - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_gre_object_info); -} - -/*************************************************************/ - -#define NM_TYPE_GRE_FACTORY (nm_gre_factory_get_type ()) -#define NM_GRE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_GRE_FACTORY, NMGreFactory)) - -static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) -{ - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_GRE, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Gre", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, - NULL); -} - -NM_DEVICE_FACTORY_DEFINE_INTERNAL (GRE, Gre, gre, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_GRE, NM_LINK_TYPE_GRETAP), - factory_iface->new_link = new_link; - ) - diff --git a/src/devices/nm-device-gre.h b/src/devices/nm-device-gre.h deleted file mode 100644 index 7acff5f7..00000000 --- a/src/devices/nm-device-gre.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- 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 2013 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_GRE_H__ -#define __NETWORKMANAGER_DEVICE_GRE_H__ - -#include - -#include "nm-device-generic.h" - -G_BEGIN_DECLS - -#define NM_TYPE_DEVICE_GRE (nm_device_gre_get_type ()) -#define NM_DEVICE_GRE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_GRE, NMDeviceGre)) -#define NM_DEVICE_GRE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_GRE, NMDeviceGreClass)) -#define NM_IS_DEVICE_GRE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_GRE)) -#define NM_IS_DEVICE_GRE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_GRE)) -#define NM_DEVICE_GRE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_GRE, NMDeviceGreClass)) - -#define NM_DEVICE_GRE_PARENT "parent" -#define NM_DEVICE_GRE_INPUT_FLAGS "input-flags" -#define NM_DEVICE_GRE_OUTPUT_FLAGS "output-flags" -#define NM_DEVICE_GRE_INPUT_KEY "input-key" -#define NM_DEVICE_GRE_OUTPUT_KEY "output-key" -#define NM_DEVICE_GRE_LOCAL "local" -#define NM_DEVICE_GRE_REMOTE "remote" -#define NM_DEVICE_GRE_TTL "ttl" -#define NM_DEVICE_GRE_TOS "tos" -#define NM_DEVICE_GRE_PATH_MTU_DISCOVERY "path-mtu-discovery" - -typedef NMDeviceGeneric NMDeviceGre; -typedef NMDeviceGenericClass NMDeviceGreClass; - -GType nm_device_gre_get_type (void); - -G_END_DECLS - -#endif /* NM_DEVICE_GRE_H */ diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index c1571fd9..45df49fe 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -20,25 +20,20 @@ #include "config.h" -#include -#include - #include +#include "nm-default.h" #include "nm-device-infiniband.h" -#include "nm-logging.h" #include "NetworkManagerUtils.h" #include "nm-device-private.h" #include "nm-enum-types.h" -#include "nm-dbus-manager.h" #include "nm-activation-request.h" #include "nm-ip4-config.h" #include "nm-platform.h" #include "nm-device-factory.h" #include "nm-core-internal.h" -#include "nm-device-infiniband-glue.h" - +#include "nmdbus-device-infiniband.h" G_DEFINE_TYPE (NMDeviceInfiniband, nm_device_infiniband, NM_TYPE_DEVICE) @@ -57,10 +52,7 @@ enum { LAST_PROP }; -static void -nm_device_infiniband_init (NMDeviceInfiniband * self) -{ -} +/*************************************************************/ static NMDeviceCapabilities get_generic_capabilities (NMDevice *dev) @@ -82,7 +74,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) NMSettingInfiniband *s_infiniband; const char *transport_mode; char *mode_path; - gboolean ok; + gboolean ok, no_firmware = FALSE; g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); @@ -93,7 +85,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) req = nm_device_get_act_request (dev); g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); g_assert (connection); s_infiniband = nm_connection_get_setting_infiniband (connection); g_assert (s_infiniband); @@ -113,8 +105,11 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) } } + /* With some drivers the interface must be down to set transport mode */ + nm_device_take_down (dev, TRUE); ok = nm_platform_sysctl_set (NM_PLATFORM_GET, mode_path, transport_mode); g_free (mode_path); + nm_device_bring_up (dev, TRUE, &no_firmware); if (!ok) { *reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED; @@ -131,7 +126,7 @@ ip4_config_pre_commit (NMDevice *self, NMIP4Config *config) NMSettingInfiniband *s_infiniband; guint32 mtu; - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); g_assert (connection); s_infiniband = nm_connection_get_setting_infiniband (connection); g_assert (s_infiniband); @@ -157,7 +152,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) if (!s_infiniband) return FALSE; - if (s_infiniband) { + if (nm_device_is_real (device)) { const char *mac; mac = nm_setting_infiniband_get_mac_address (s_infiniband); @@ -234,12 +229,69 @@ update_connection (NMDevice *device, NMConnection *connection) ifindex = nm_device_get_ifindex (device); if (ifindex > 0) { - if (!nm_platform_infiniband_get_info (NM_PLATFORM_GET, ifindex, NULL, NULL, &transport_mode)) + if (!nm_platform_link_infiniband_get_properties (NM_PLATFORM_GET, ifindex, NULL, NULL, &transport_mode)) transport_mode = "datagram"; } g_object_set (G_OBJECT (s_infiniband), NM_SETTING_INFINIBAND_TRANSPORT_MODE, transport_mode, NULL); } +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) +{ + NMSettingInfiniband *s_infiniband; + int parent_ifindex, p_key; + NMPlatformError plerr; + + if (!NM_IS_DEVICE_INFINIBAND (parent)) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Parent interface %s must be an InfiniBand interface", + nm_device_get_iface (parent)); + return FALSE; + } + + s_infiniband = nm_connection_get_setting_infiniband (connection); + + /* Can only create partitions at this time */ + p_key = nm_setting_infiniband_get_p_key (s_infiniband); + if (p_key < 0) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "only InfiniBand partitions can be created"); + return FALSE; + } + + parent_ifindex = nm_device_get_ifindex (parent); + if (parent_ifindex <= 0) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "failed to get InfiniBand parent %s ifindex", + nm_device_get_iface (parent)); + return FALSE; + } + + plerr = nm_platform_link_infiniband_add (NM_PLATFORM_GET, parent_ifindex, p_key, out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create InfiniBand P_Key interface '%s' for '%s': %s", + nm_device_get_iface (device), + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; + } + + NM_DEVICE_INFINIBAND_GET_PRIVATE (device)->is_partition = TRUE; + return TRUE; +} + +/*************************************************************/ + +static void +nm_device_infiniband_init (NMDeviceInfiniband * self) +{ +} + static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) @@ -276,10 +328,13 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) g_type_class_add_private (object_class, sizeof (NMDeviceInfinibandPrivate)); + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_INFINIBAND_SETTING_NAME, NM_LINK_TYPE_INFINIBAND) + /* virtual methods */ object_class->get_property = get_property; object_class->set_property = set_property; + parent_class->create_and_realize = create_and_realize; parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->check_connection_compatible = check_connection_compatible; parent_class->complete_connection = complete_connection; @@ -296,9 +351,9 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_infiniband_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_INFINIBAND_SKELETON, + NULL); } /*************************************************************/ @@ -307,60 +362,33 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) #define NM_INFINIBAND_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_INFINIBAND_FACTORY, NMInfinibandFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_INFINIBAND, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "InfiniBand", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND, - NM_DEVICE_INFINIBAND_IS_PARTITION, (plink->parent > 0 || plink->parent == NM_PLATFORM_LINK_OTHER_NETNS), - NULL); -} - -static NMDevice * -create_virtual_device_for_connection (NMDeviceFactory *factory, - NMConnection *connection, - NMDevice *parent, - GError **error) -{ - NMSettingInfiniband *s_infiniband; - int p_key, parent_ifindex; - const char *iface; - NMPlatformError plerr; - const NMPlatformLink *plink; - - if (!NM_IS_DEVICE_INFINIBAND (parent)) { - g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, - "Parent interface %s must be an InfiniBand interface", - nm_device_get_iface (parent)); - return NULL; - } - - s_infiniband = nm_connection_get_setting_infiniband (connection); - - iface = nm_setting_infiniband_get_virtual_interface_name (s_infiniband); - g_assert (iface); - - parent_ifindex = nm_device_get_ifindex (parent); - p_key = nm_setting_infiniband_get_p_key (s_infiniband); - - plerr = nm_platform_infiniband_partition_add (NM_PLATFORM_GET, parent_ifindex, p_key, NULL); - if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { - g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create InfiniBand P_Key interface '%s' for '%s': %s", - iface, - nm_connection_get_id (connection), - nm_platform_error_to_string (plerr)); - return NULL; + gboolean is_partition = FALSE; + + if (plink) + is_partition = (plink->parent > 0 || plink->parent == NM_PLATFORM_LINK_OTHER_NETNS); + else if (connection) { + NMSettingInfiniband *s_infiniband; + + s_infiniband = nm_connection_get_setting_infiniband (connection); + g_return_val_if_fail (s_infiniband, NULL); + is_partition = !!nm_setting_infiniband_get_parent (s_infiniband) + || ( nm_setting_infiniband_get_p_key (s_infiniband) >= 0 + && nm_setting_infiniband_get_mac_address (s_infiniband)); } - plink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, iface); return (NMDevice *) g_object_new (NM_TYPE_DEVICE_INFINIBAND, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_DRIVER, nm_device_get_driver (parent), + NM_DEVICE_IFACE, iface, NM_DEVICE_TYPE_DESC, "InfiniBand", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND, - NM_DEVICE_INFINIBAND_IS_PARTITION, TRUE, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_INFINIBAND, + /* XXX: Partition should probably be a different link type! */ + NM_DEVICE_INFINIBAND_IS_PARTITION, is_partition, NULL); } @@ -400,8 +428,7 @@ get_virtual_iface_name (NMDeviceFactory *factory, NM_DEVICE_FACTORY_DEFINE_INTERNAL (INFINIBAND, Infiniband, infiniband, NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_INFINIBAND) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_INFINIBAND_SETTING_NAME), - factory_iface->new_link = new_link; - factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; + factory_iface->create_device = create_device; factory_iface->get_connection_parent = get_connection_parent; factory_iface->get_virtual_iface_name = get_virtual_iface_name; ) diff --git a/src/devices/nm-device-infiniband.h b/src/devices/nm-device-infiniband.h index b81b762a..cac9a79d 100644 --- a/src/devices/nm-device-infiniband.h +++ b/src/devices/nm-device-infiniband.h @@ -21,8 +21,6 @@ #ifndef __NETWORKMANAGER_DEVICE_INFINIBAND_H__ #define __NETWORKMANAGER_DEVICE_INFINIBAND_H__ -#include - #include "nm-device.h" G_BEGIN_DECLS diff --git a/src/devices/nm-device-ip-tunnel.c b/src/devices/nm-device-ip-tunnel.c new file mode 100644 index 00000000..6d0df059 --- /dev/null +++ b/src/devices/nm-device-ip-tunnel.c @@ -0,0 +1,1052 @@ +/* -*- 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 2015 Red Hat, Inc. + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "nm-device-ip-tunnel.h" +#include "nm-device-private.h" +#include "nm-default.h" +#include "nm-manager.h" +#include "nm-platform.h" +#include "nm-device-factory.h" +#include "nm-core-internal.h" +#include "nm-connection-provider.h" +#include "nm-activation-request.h" +#include "nm-ip4-config.h" + +#include "nmdbus-device-ip-tunnel.h" + +#include "nm-device-logging.h" +_LOG_DECLARE_SELF(NMDeviceIPTunnel); + +G_DEFINE_TYPE (NMDeviceIPTunnel, nm_device_ip_tunnel, NM_TYPE_DEVICE) + +#define NM_DEVICE_IP_TUNNEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelPrivate)) + +typedef struct { + NMIPTunnelMode mode; + NMDevice *parent; + int parent_ifindex; + char *local; + char *remote; + guint8 ttl; + guint8 tos; + gboolean path_mtu_discovery; + int addr_family; + char *input_key; + char *output_key; + guint8 encap_limit; + guint32 flow_label; +} NMDeviceIPTunnelPrivate; + +enum { + PROP_0, + PROP_MODE, + PROP_PARENT, + PROP_LOCAL, + PROP_REMOTE, + PROP_TTL, + PROP_TOS, + PROP_PATH_MTU_DISCOVERY, + PROP_INPUT_KEY, + PROP_OUTPUT_KEY, + PROP_ENCAPSULATION_LIMIT, + PROP_FLOW_LABEL, + + LAST_PROP +}; + +/**************************************************************/ + +static gboolean +address_equal_pp (int family, const char *a, const char *b) +{ + char buffer1[sizeof (struct in6_addr)] = { }; + char buffer2[sizeof (struct in6_addr)] = { }; + + g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); + + if (a) + inet_pton (family, a, buffer1); + if (b) + inet_pton (family, b, buffer2); + + return !memcmp (buffer1, buffer2, + family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr)); +} + +static gboolean +address_equal_pn (int family, const char *a, const void *b) +{ + char buffer1[sizeof (struct in6_addr)] = { }; + + g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); + + if (a) + inet_pton (family, a, buffer1); + + return !memcmp (buffer1, b, + family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr)); + +} + +static void +update_properties_from_ifindex (NMDevice *device, int ifindex) +{ + NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device); + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self); + GObject *object = G_OBJECT (device); + NMDevice *parent; + int parent_ifindex; + in_addr_t local4, remote4; + struct in6_addr local6, remote6; + guint8 ttl = 0, tos = 0, encap_limit = 0; + gboolean pmtud = FALSE; + guint32 flow_label = 0; + char *key; + + if (ifindex <= 0) { +clear: + if (priv->parent || priv->parent_ifindex) { + g_clear_object (&priv->parent); + priv->parent_ifindex = 0; + g_object_notify (object, NM_DEVICE_IP_TUNNEL_PARENT); + } + if (priv->local) { + g_clear_pointer (&priv->local, g_free); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_LOCAL); + } + if (priv->remote) { + g_clear_pointer (&priv->remote, g_free); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_REMOTE); + } + if (priv->input_key) { + g_clear_pointer (&priv->input_key, g_free); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_INPUT_KEY); + } + if (priv->output_key) { + g_clear_pointer (&priv->output_key, g_free); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_OUTPUT_KEY); + } + + goto out; + } + + if (priv->mode == NM_IP_TUNNEL_MODE_GRE) { + const NMPlatformLnkGre *lnk; + + lnk = nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, ifindex, NULL); + if (!lnk) { + _LOGW (LOGD_HW, "could not read %s properties", "gre"); + goto clear; + } + + parent_ifindex = lnk->parent_ifindex; + local4 = lnk->local; + remote4 = lnk->remote; + ttl = lnk->ttl; + tos = lnk->tos; + pmtud = lnk->path_mtu_discovery; + + if (NM_FLAGS_HAS (lnk->input_flags, NM_GRE_KEY)) { + key = g_strdup_printf ("%u", lnk->input_key); + if (g_strcmp0 (priv->input_key, key)) { + g_free (priv->input_key); + priv->input_key = key; + g_object_notify (object, NM_DEVICE_IP_TUNNEL_INPUT_KEY); + } else + g_free (key); + } else { + if (priv->input_key) { + g_clear_pointer (&priv->input_key, g_free); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_INPUT_KEY); + } + } + + if (NM_FLAGS_HAS (lnk->output_flags, NM_GRE_KEY)) { + key = g_strdup_printf ("%u", lnk->output_key); + if (g_strcmp0 (priv->output_key, key)) { + g_free (priv->output_key); + priv->output_key = key; + g_object_notify (object, NM_DEVICE_IP_TUNNEL_OUTPUT_KEY); + } else + g_free (key); + } else { + if (priv->output_key) { + g_clear_pointer (&priv->output_key, g_free); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_OUTPUT_KEY); + } + } + } else if (priv->mode == NM_IP_TUNNEL_MODE_SIT) { + const NMPlatformLnkSit *lnk; + + lnk = nm_platform_link_get_lnk_sit (NM_PLATFORM_GET, ifindex, NULL); + if (!lnk) { + _LOGW (LOGD_HW, "could not read %s properties", "sit"); + goto clear; + } + + parent_ifindex = lnk->parent_ifindex; + local4 = lnk->local; + remote4 = lnk->remote; + ttl = lnk->ttl; + tos = lnk->tos; + pmtud = lnk->path_mtu_discovery; + } else if (priv->mode == NM_IP_TUNNEL_MODE_IPIP) { + const NMPlatformLnkIpIp *lnk; + + lnk = nm_platform_link_get_lnk_ipip (NM_PLATFORM_GET, ifindex, NULL); + if (!lnk) { + _LOGW (LOGD_HW, "could not read %s properties", "ipip"); + goto clear; + } + + parent_ifindex = lnk->parent_ifindex; + local4 = lnk->local; + remote4 = lnk->remote; + ttl = lnk->ttl; + tos = lnk->tos; + pmtud = lnk->path_mtu_discovery; + } else if ( priv->mode == NM_IP_TUNNEL_MODE_IPIP6 + || priv->mode == NM_IP_TUNNEL_MODE_IP6IP6) { + const NMPlatformLnkIp6Tnl *lnk; + + lnk = nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, ifindex, NULL); + if (!lnk) { + _LOGW (LOGD_HW, "could not read %s properties", "ip6tnl"); + goto clear; + } + + parent_ifindex = lnk->parent_ifindex; + local6 = lnk->local; + remote6 = lnk->remote; + ttl = lnk->ttl; + tos = lnk->tclass; + encap_limit = lnk->encap_limit; + flow_label = lnk->flow_label; + } else + g_return_if_reached (); + + if (priv->parent_ifindex != parent_ifindex) { + g_clear_object (&priv->parent); + priv->parent_ifindex = parent_ifindex; + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); + if (parent) + priv->parent = g_object_ref (parent); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_PARENT); + } + + if (priv->addr_family == AF_INET) { + if (!address_equal_pn (AF_INET, priv->local, &local4)) { + g_clear_pointer (&priv->local, g_free); + if (local4) + priv->local = g_strdup (nm_utils_inet4_ntop (local4, NULL)); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_LOCAL); + } + + if (!address_equal_pn (AF_INET, priv->remote, &remote4)) { + g_clear_pointer (&priv->remote, g_free); + if (remote4) + priv->remote = g_strdup (nm_utils_inet4_ntop (remote4, NULL)); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_REMOTE); + } + } else { + if (!address_equal_pn (AF_INET6, priv->local, &local6)) { + g_clear_pointer (&priv->local, g_free); + if (memcmp (&local6, &in6addr_any, sizeof (in6addr_any))) + priv->local = g_strdup (nm_utils_inet6_ntop (&local6, NULL)); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_LOCAL); + } + + if (!address_equal_pn (AF_INET6, priv->remote, &remote6)) { + g_clear_pointer (&priv->remote, g_free); + if (memcmp (&remote6, &in6addr_any, sizeof (in6addr_any))) + priv->remote = g_strdup (nm_utils_inet6_ntop (&remote6, NULL)); + g_object_notify (object, NM_DEVICE_IP_TUNNEL_REMOTE); + } + } + +out: + + if (priv->ttl != ttl) { + priv->ttl = ttl; + g_object_notify (object, NM_DEVICE_IP_TUNNEL_TTL); + } + + if (priv->tos != tos) { + priv->tos = tos; + g_object_notify (object, NM_DEVICE_IP_TUNNEL_TOS); + } + + if (priv->path_mtu_discovery != pmtud) { + priv->path_mtu_discovery = pmtud; + g_object_notify (object, NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY); + } + + if (priv->encap_limit != encap_limit) { + priv->encap_limit = encap_limit; + g_object_notify (object, NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT); + } + + if (priv->flow_label != flow_label) { + priv->flow_label = flow_label; + g_object_notify (object, NM_DEVICE_IP_TUNNEL_FLOW_LABEL); + } +} + +static void +update_properties (NMDevice *device) +{ + update_properties_from_ifindex (device, nm_device_get_ifindex (device)); +} + +static void +link_changed (NMDevice *device, NMPlatformLink *info) +{ + NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->link_changed (device, info); + update_properties (device); +} + +static gboolean +complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMSettingIPTunnel *s_ip_tunnel; + + nm_utils_complete_generic (connection, + NM_SETTING_IP_TUNNEL_SETTING_NAME, + existing_connections, + NULL, + _("IP tunnel connection"), + NULL, + TRUE); + + s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); + if (!s_ip_tunnel) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, + "A 'tunnel' setting is required."); + return FALSE; + } + + return TRUE; +} + +static void +update_connection (NMDevice *device, NMConnection *connection) +{ + NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device); + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self); + NMSettingIPTunnel *s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); + NMDevice *parent = NULL; + const char *setting_parent, *new_parent; + + if (!s_ip_tunnel) { + s_ip_tunnel = (NMSettingIPTunnel *) nm_setting_ip_tunnel_new (); + nm_connection_add_setting (connection, (NMSetting *) s_ip_tunnel); + } + + if (nm_setting_ip_tunnel_get_mode (s_ip_tunnel) != priv->mode) + g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_MODE, priv->mode, NULL); + + if (priv->parent_ifindex > 0) + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->parent_ifindex); + + /* Update parent in the connection; default to parent's interface name */ + if (parent) { + new_parent = nm_device_get_iface (parent); + setting_parent = nm_setting_ip_tunnel_get_parent (s_ip_tunnel); + if (setting_parent && nm_utils_is_uuid (setting_parent)) { + NMConnection *parent_connection; + + /* Don't change a parent specified by UUID if it's still valid */ + parent_connection = nm_connection_provider_get_connection_by_uuid (nm_connection_provider_get (), + setting_parent); + if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection)) + new_parent = NULL; + } + if (new_parent) + g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_PARENT, new_parent, NULL); + } else + g_object_set (s_ip_tunnel, NM_SETTING_IP_TUNNEL_PARENT, NULL, NULL); + + if (!address_equal_pp (priv->addr_family, + nm_setting_ip_tunnel_get_local (s_ip_tunnel), + priv->local)) + g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_LOCAL, priv->local, NULL); + + if (!address_equal_pp (priv->addr_family, + nm_setting_ip_tunnel_get_remote (s_ip_tunnel), + priv->remote)) + g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_REMOTE, priv->remote, NULL); + + if (nm_setting_ip_tunnel_get_ttl (s_ip_tunnel) != priv->ttl) + g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_TTL, priv->ttl, NULL); + + if (nm_setting_ip_tunnel_get_tos (s_ip_tunnel) != priv->tos) + g_object_set (G_OBJECT (s_ip_tunnel), NM_SETTING_IP_TUNNEL_TOS, priv->tos, NULL); + + if (nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel) != priv->path_mtu_discovery) { + g_object_set (G_OBJECT (s_ip_tunnel), + NM_SETTING_IP_TUNNEL_PATH_MTU_DISCOVERY, + priv->path_mtu_discovery, + NULL); + } + + if (nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel) != priv->encap_limit) { + g_object_set (G_OBJECT (s_ip_tunnel), + NM_SETTING_IP_TUNNEL_ENCAPSULATION_LIMIT, + priv->encap_limit, + NULL); + } + + if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label) { + g_object_set (G_OBJECT (s_ip_tunnel), + NM_SETTING_IP_TUNNEL_FLOW_LABEL, + priv->flow_label, + NULL); + } + + if (priv->mode == NM_IP_TUNNEL_MODE_GRE || priv->mode == NM_IP_TUNNEL_MODE_IP6GRE) { + if (g_strcmp0 (nm_setting_ip_tunnel_get_input_key (s_ip_tunnel), priv->input_key)) { + g_object_set (G_OBJECT (s_ip_tunnel), + NM_SETTING_IP_TUNNEL_INPUT_KEY, + priv->input_key, + NULL); + } + if (g_strcmp0 (nm_setting_ip_tunnel_get_output_key (s_ip_tunnel), priv->output_key)) { + g_object_set (G_OBJECT (s_ip_tunnel), + NM_SETTING_IP_TUNNEL_OUTPUT_KEY, + priv->output_key, + NULL); + } + } +} + +static gboolean +match_parent (NMDevice *dev_parent, const char *setting_parent) +{ + g_return_val_if_fail (setting_parent, FALSE); + + if (!dev_parent) + return FALSE; + + if (nm_utils_is_uuid (setting_parent)) { + NMActRequest *parent_req; + NMConnection *parent_connection; + + /* If the parent is a UUID, the connection matches if our parent + * device has that connection activated. + */ + parent_req = nm_device_get_act_request (dev_parent); + if (!parent_req) + return FALSE; + + parent_connection = nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (parent_req)); + if (!parent_connection) + return FALSE; + + if (g_strcmp0 (setting_parent, nm_connection_get_uuid (parent_connection)) != 0) + return FALSE; + } else { + /* interface name */ + if (g_strcmp0 (setting_parent, nm_device_get_ip_iface (dev_parent)) != 0) + return FALSE; + } + + return TRUE; +} + +static gboolean +check_connection_compatible (NMDevice *device, NMConnection *connection) +{ + NMDeviceIPTunnel *self = NM_DEVICE_IP_TUNNEL (device); + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (self); + NMSettingIPTunnel *s_ip_tunnel; + const char *parent; + + if (!NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->check_connection_compatible (device, connection)) + return FALSE; + + s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); + if (!s_ip_tunnel) + return FALSE; + + if (nm_setting_ip_tunnel_get_mode (s_ip_tunnel) != priv->mode) + return FALSE; + + if (nm_device_is_real (device)) { + /* Check parent interface; could be an interface name or a UUID */ + parent = nm_setting_ip_tunnel_get_parent (s_ip_tunnel); + if (parent) { + if (!match_parent (priv->parent, parent)) + return FALSE; + } + + if (!address_equal_pp (priv->addr_family, + nm_setting_ip_tunnel_get_local (s_ip_tunnel), + priv->local)) + return FALSE; + + if (!address_equal_pp (priv->addr_family, + nm_setting_ip_tunnel_get_remote (s_ip_tunnel), + priv->remote)) + return FALSE; + + if (nm_setting_ip_tunnel_get_ttl (s_ip_tunnel) != priv->ttl) + return FALSE; + + if (nm_setting_ip_tunnel_get_tos (s_ip_tunnel) != priv->tos) + return FALSE; + + if (priv->addr_family == AF_INET) { + if (nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel) != priv->path_mtu_discovery) + return FALSE; + } else { + if (nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel) != priv->encap_limit) + return FALSE; + + if (nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel) != priv->flow_label) + return FALSE; + } + } + + return TRUE; +} + +static NMIPTunnelMode +platform_link_to_tunnel_mode (const NMPlatformLink *link) +{ + const NMPlatformLnkIp6Tnl *lnk; + + switch (link->type) { + case NM_LINK_TYPE_GRE: + return NM_IP_TUNNEL_MODE_GRE; + case NM_LINK_TYPE_IP6TNL: + lnk = nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, link->ifindex, NULL); + if (lnk->proto == IPPROTO_IPIP) + return NM_IP_TUNNEL_MODE_IPIP6; + else if (lnk->proto == IPPROTO_IPV6) + return NM_IP_TUNNEL_MODE_IP6IP6; + else + return NM_IP_TUNNEL_MODE_UKNOWN; + case NM_LINK_TYPE_IPIP: + return NM_IP_TUNNEL_MODE_IPIP; + case NM_LINK_TYPE_SIT: + return NM_IP_TUNNEL_MODE_SIT; + default: + g_return_val_if_reached (NM_IP_TUNNEL_MODE_UKNOWN); + } +} + +static NMLinkType +tunnel_mode_to_link_type (NMIPTunnelMode tunnel_mode) +{ + switch (tunnel_mode) { + case NM_IP_TUNNEL_MODE_GRE: + return NM_LINK_TYPE_GRE; + case NM_IP_TUNNEL_MODE_IPIP6: + case NM_IP_TUNNEL_MODE_IP6IP6: + return NM_LINK_TYPE_IP6TNL; + case NM_IP_TUNNEL_MODE_IPIP: + return NM_LINK_TYPE_IPIP; + case NM_IP_TUNNEL_MODE_SIT: + return NM_LINK_TYPE_SIT; + default: + g_return_val_if_reached (NM_LINK_TYPE_UNKNOWN); + } +} + +/**************************************************************/ + +static void +nm_device_ip_tunnel_init (NMDeviceIPTunnel *self) +{ +} + +static void +constructed (GObject *object) +{ + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object); + + if ( priv->mode == NM_IP_TUNNEL_MODE_IPIP6 + || priv->mode == NM_IP_TUNNEL_MODE_IP6IP6) + priv->addr_family = AF_INET6; + else + priv->addr_family = AF_INET; + + G_OBJECT_CLASS (nm_device_ip_tunnel_parent_class)->constructed (object); +} + +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) +{ + const char *iface = nm_device_get_iface (device); + NMSettingIPTunnel *s_ip_tunnel; + NMPlatformError plerr; + NMPlatformLnkGre lnk_gre = { }; + NMPlatformLnkSit lnk_sit = { }; + NMPlatformLnkIpIp lnk_ipip = { }; + NMPlatformLnkIp6Tnl lnk_ip6tnl = { }; + const char *str; + gint64 val; + + s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); + g_assert (s_ip_tunnel); + + switch (nm_setting_ip_tunnel_get_mode (s_ip_tunnel)) { + case NM_IP_TUNNEL_MODE_GRE: + if (parent) + lnk_gre.parent_ifindex = nm_device_get_ifindex (parent); + + str = nm_setting_ip_tunnel_get_local (s_ip_tunnel); + if (str) + inet_pton (AF_INET, str, &lnk_gre.local); + + str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel); + g_assert (str); + inet_pton (AF_INET, str, &lnk_gre.remote); + + lnk_gre.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel); + lnk_gre.tos = nm_setting_ip_tunnel_get_tos (s_ip_tunnel); + lnk_gre.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel); + + val = _nm_utils_ascii_str_to_int64 (nm_setting_ip_tunnel_get_input_key (s_ip_tunnel), + 10, + 0, + G_MAXUINT32, + -1); + if (val != -1) { + lnk_gre.input_key = val; + lnk_gre.input_flags = NM_GRE_KEY; + } + + val = _nm_utils_ascii_str_to_int64 (nm_setting_ip_tunnel_get_output_key (s_ip_tunnel), + 10, + 0, + G_MAXUINT32, + -1); + if (val != -1) { + lnk_gre.output_key = val; + lnk_gre.output_flags = NM_GRE_KEY; + } + + plerr = nm_platform_link_gre_add (NM_PLATFORM_GET, iface, &lnk_gre, out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create GRE interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; + } + break; + case NM_IP_TUNNEL_MODE_SIT: + if (parent) + lnk_sit.parent_ifindex = nm_device_get_ifindex (parent); + + str = nm_setting_ip_tunnel_get_local (s_ip_tunnel); + if (str) + inet_pton (AF_INET, str, &lnk_sit.local); + + str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel); + g_assert (str); + inet_pton (AF_INET, str, &lnk_sit.remote); + + lnk_sit.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel); + lnk_sit.tos = nm_setting_ip_tunnel_get_tos (s_ip_tunnel); + lnk_sit.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel); + + plerr = nm_platform_link_sit_add (NM_PLATFORM_GET, iface, &lnk_sit, out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create SIT interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; + } + break; + case NM_IP_TUNNEL_MODE_IPIP: + if (parent) + lnk_ipip.parent_ifindex = nm_device_get_ifindex (parent); + + str = nm_setting_ip_tunnel_get_local (s_ip_tunnel); + if (str) + inet_pton (AF_INET, str, &lnk_ipip.local); + + str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel); + g_assert (str); + inet_pton (AF_INET, str, &lnk_ipip.remote); + + lnk_ipip.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel); + lnk_ipip.tos = nm_setting_ip_tunnel_get_tos (s_ip_tunnel); + lnk_ipip.path_mtu_discovery = nm_setting_ip_tunnel_get_path_mtu_discovery (s_ip_tunnel); + + plerr = nm_platform_link_ipip_add (NM_PLATFORM_GET, iface, &lnk_ipip, out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create IPIP interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; + } + break; + case NM_IP_TUNNEL_MODE_IPIP6: + case NM_IP_TUNNEL_MODE_IP6IP6: + if (parent) + lnk_ip6tnl.parent_ifindex = nm_device_get_ifindex (parent); + + str = nm_setting_ip_tunnel_get_local (s_ip_tunnel); + if (str) + inet_pton (AF_INET6, str, &lnk_ip6tnl.local); + + str = nm_setting_ip_tunnel_get_remote (s_ip_tunnel); + g_assert (str); + inet_pton (AF_INET6, str, &lnk_ip6tnl.remote); + + lnk_ip6tnl.ttl = nm_setting_ip_tunnel_get_ttl (s_ip_tunnel); + lnk_ip6tnl.tclass = nm_setting_ip_tunnel_get_tos (s_ip_tunnel); + lnk_ip6tnl.encap_limit = nm_setting_ip_tunnel_get_encapsulation_limit (s_ip_tunnel); + lnk_ip6tnl.flow_label = nm_setting_ip_tunnel_get_flow_label (s_ip_tunnel); + lnk_ip6tnl.proto = nm_setting_ip_tunnel_get_mode (s_ip_tunnel) == NM_IP_TUNNEL_MODE_IPIP6 ? IPPROTO_IPIP : IPPROTO_IPV6; + + plerr = nm_platform_link_ip6tnl_add (NM_PLATFORM_GET, iface, &lnk_ip6tnl, out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create IPIP interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; + } + break; + default: + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create IP tunnel interface '%s' for '%s': mode %d not supported", + iface, + nm_connection_get_id (connection), + (int) nm_setting_ip_tunnel_get_mode (s_ip_tunnel)); + return FALSE; + } + + return TRUE; +} + +static void +realize_start_notify (NMDevice *device, const NMPlatformLink *plink) +{ + NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->realize_start_notify (device, plink); + + update_properties (device); +} + +static void +ip4_config_pre_commit (NMDevice *device, NMIP4Config *config) +{ + NMConnection *connection; + NMSettingIPTunnel *s_ip_tunnel; + guint32 mtu; + + connection = nm_device_get_applied_connection (device); + g_assert (connection); + s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); + g_assert (s_ip_tunnel); + + /* MTU override */ + mtu = nm_setting_ip_tunnel_get_mtu (s_ip_tunnel); + if (mtu) + nm_ip4_config_set_mtu (config, mtu, NM_IP_CONFIG_SOURCE_USER); +} + +static void +unrealize_notify (NMDevice *device) +{ + NM_DEVICE_CLASS (nm_device_ip_tunnel_parent_class)->unrealize_notify (device); + + update_properties_from_ifindex (device, 0); +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object); + NMDevice *parent; + + switch (prop_id) { + case PROP_MODE: + g_value_set_uint (value, priv->mode); + break; + case PROP_PARENT: + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->parent_ifindex); + nm_utils_g_value_set_object_path (value, parent); + break; + case PROP_LOCAL: + g_value_set_string (value, priv->local); + break; + case PROP_REMOTE: + g_value_set_string (value, priv->remote); + break; + case PROP_TTL: + g_value_set_uchar (value, priv->ttl); + break; + case PROP_TOS: + g_value_set_uchar (value, priv->tos); + break; + case PROP_PATH_MTU_DISCOVERY: + g_value_set_boolean (value, priv->path_mtu_discovery); + break; + case PROP_INPUT_KEY: + g_value_set_string (value, priv->input_key); + break; + case PROP_OUTPUT_KEY: + g_value_set_string (value, priv->output_key); + break; + case PROP_ENCAPSULATION_LIMIT: + g_value_set_uchar (value, priv->encap_limit); + break; + case PROP_FLOW_LABEL: + g_value_set_uint (value, priv->flow_label); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMDeviceIPTunnelPrivate *priv = NM_DEVICE_IP_TUNNEL_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_MODE: + priv->mode = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); + + g_type_class_add_private (klass, sizeof (NMDeviceIPTunnelPrivate)); + + object_class->constructed = constructed; + object_class->get_property = get_property; + object_class->set_property = set_property; + + device_class->link_changed = link_changed; + device_class->complete_connection = complete_connection; + device_class->update_connection = update_connection; + device_class->check_connection_compatible = check_connection_compatible; + device_class->create_and_realize = create_and_realize; + device_class->ip4_config_pre_commit = ip4_config_pre_commit; + device_class->realize_start_notify = realize_start_notify; + device_class->unrealize_notify = unrealize_notify; + + NM_DEVICE_CLASS_DECLARE_TYPES (klass, + NM_SETTING_IP_TUNNEL_SETTING_NAME, + NM_LINK_TYPE_GRE, + NM_LINK_TYPE_IP6TNL, + NM_LINK_TYPE_IPIP, + NM_LINK_TYPE_SIT); + + /* properties */ + g_object_class_install_property + (object_class, PROP_MODE, + g_param_spec_uint (NM_DEVICE_IP_TUNNEL_MODE, "", "", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + /* properties */ + g_object_class_install_property + (object_class, PROP_PARENT, + g_param_spec_string (NM_DEVICE_IP_TUNNEL_PARENT, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_LOCAL, + g_param_spec_string (NM_DEVICE_IP_TUNNEL_LOCAL, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_REMOTE, + g_param_spec_string (NM_DEVICE_IP_TUNNEL_REMOTE, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_TTL, + g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_TTL, "", "", + 0, 255, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_TOS, + g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_TOS, "", "", + 0, 255, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_PATH_MTU_DISCOVERY, + g_param_spec_boolean (NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY, "", "", + FALSE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_INPUT_KEY, + g_param_spec_string (NM_DEVICE_IP_TUNNEL_INPUT_KEY, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_OUTPUT_KEY, + g_param_spec_string (NM_DEVICE_IP_TUNNEL_OUTPUT_KEY, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_ENCAPSULATION_LIMIT, + g_param_spec_uchar (NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT, "", "", + 0, 255, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_FLOW_LABEL, + g_param_spec_uint (NM_DEVICE_IP_TUNNEL_FLOW_LABEL, "", "", + 0, (1 << 20) - 1, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_IPTUNNEL_SKELETON, + NULL); +} +/*************************************************************/ + +#define NM_TYPE_IP_TUNNEL_FACTORY (nm_ip_tunnel_factory_get_type ()) +#define NM_IP_TUNNEL_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IP_TUNNEL_FACTORY, NMIPTunnelFactory)) + +static NMDevice * +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) +{ + NMSettingIPTunnel *s_ip_tunnel; + NMIPTunnelMode mode; + NMLinkType link_type; + + if (connection) { + s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); + mode = nm_setting_ip_tunnel_get_mode (s_ip_tunnel); + link_type = tunnel_mode_to_link_type (mode); + } else { + link_type = plink->type; + mode = platform_link_to_tunnel_mode (plink); + } + + if (mode == NM_IP_TUNNEL_MODE_UKNOWN) + return NULL; + + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_IP_TUNNEL, + NM_DEVICE_IFACE, iface, + NM_DEVICE_TYPE_DESC, "IPTunnel", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_IP_TUNNEL, + NM_DEVICE_LINK_TYPE, link_type, + NM_DEVICE_IP_TUNNEL_MODE, mode, + NULL); +} + +static const char * +get_connection_parent (NMDeviceFactory *factory, NMConnection *connection) +{ + NMSettingIPTunnel *s_ip_tunnel; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_IP_TUNNEL_SETTING_NAME), NULL); + + s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); + g_assert (s_ip_tunnel); + + return nm_setting_ip_tunnel_get_parent (s_ip_tunnel); +} + +static char * +get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + const char *ifname; + NMSettingIPTunnel *s_ip_tunnel; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_IP_TUNNEL_SETTING_NAME), NULL); + + s_ip_tunnel = nm_connection_get_setting_ip_tunnel (connection); + g_assert (s_ip_tunnel); + + if (nm_setting_ip_tunnel_get_parent (s_ip_tunnel) && !parent_iface) + return NULL; + + ifname = nm_connection_get_interface_name (connection); + + return g_strdup (ifname); +} + +NM_DEVICE_FACTORY_DEFINE_INTERNAL (IP_TUNNEL, IPTunnel, ip_tunnel, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_GRE, NM_LINK_TYPE_SIT, NM_LINK_TYPE_IPIP) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_IP_TUNNEL_SETTING_NAME), + factory_iface->create_device = create_device; + factory_iface->get_connection_parent = get_connection_parent; + factory_iface->get_virtual_iface_name = get_virtual_iface_name; +) diff --git a/src/devices/nm-device-ip-tunnel.h b/src/devices/nm-device-ip-tunnel.h new file mode 100644 index 00000000..11cb5bce --- /dev/null +++ b/src/devices/nm-device-ip-tunnel.h @@ -0,0 +1,60 @@ +/* -*- 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 2015 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_DEVICE_IP_TUNNEL_H__ +#define __NETWORKMANAGER_DEVICE_IP_TUNNEL_H__ + +#include "nm-core-types.h" +#include "nm-device.h" + +G_BEGIN_DECLS + +#define NM_TYPE_DEVICE_IP_TUNNEL (nm_device_ip_tunnel_get_type ()) +#define NM_DEVICE_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnel)) +#define NM_DEVICE_IP_TUNNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelClass)) +#define NM_IS_DEVICE_IP_TUNNEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_IP_TUNNEL)) +#define NM_IS_DEVICE_IP_TUNNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_IP_TUNNEL)) +#define NM_DEVICE_IP_TUNNEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_IP_TUNNEL, NMDeviceIPTunnelClass)) + +#define NM_DEVICE_IP_TUNNEL_MODE "mode" +#define NM_DEVICE_IP_TUNNEL_PARENT "parent" +#define NM_DEVICE_IP_TUNNEL_LOCAL "local" +#define NM_DEVICE_IP_TUNNEL_REMOTE "remote" +#define NM_DEVICE_IP_TUNNEL_TTL "ttl" +#define NM_DEVICE_IP_TUNNEL_TOS "tos" +#define NM_DEVICE_IP_TUNNEL_PATH_MTU_DISCOVERY "path-mtu-discovery" +#define NM_DEVICE_IP_TUNNEL_INPUT_KEY "input-key" +#define NM_DEVICE_IP_TUNNEL_OUTPUT_KEY "output-key" +#define NM_DEVICE_IP_TUNNEL_ENCAPSULATION_LIMIT "encapsulation-limit" +#define NM_DEVICE_IP_TUNNEL_FLOW_LABEL "flow-label" + +typedef struct { + NMDevice parent; +} NMDeviceIPTunnel; + +typedef struct { + NMDeviceClass parent; +} NMDeviceIPTunnelClass; + +GType nm_device_ip_tunnel_get_type (void); + +G_END_DECLS + +#endif /* NM_DEVICE_IP_TUNNEL_H */ diff --git a/src/devices/nm-device-logging.h b/src/devices/nm-device-logging.h index f3b76ee8..6255d6f3 100644 --- a/src/devices/nm-device-logging.h +++ b/src/devices/nm-device-logging.h @@ -21,7 +21,7 @@ #ifndef __NETWORKMANAGER_DEVICE_LOGGING_H__ #define __NETWORKMANAGER_DEVICE_LOGGING_H__ -#include "nm-logging.h" +#include "nm-default.h" #include "nm-device.h" #define _LOG_DECLARE_SELF(t) \ diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index 2a815cfd..8123a793 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -15,32 +15,41 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2013 Red Hat, Inc. + * Copyright 2013 - 2015 Red Hat, Inc. */ #include "config.h" #include +#include "nm-default.h" #include "nm-device-macvlan.h" #include "nm-device-private.h" -#include "nm-dbus-manager.h" -#include "nm-logging.h" +#include "nm-connection-provider.h" +#include "nm-activation-request.h" #include "nm-manager.h" #include "nm-platform.h" #include "nm-device-factory.h" +#include "nm-setting-macvlan.h" +#include "nm-setting-wired.h" +#include "nm-active-connection.h" +#include "nm-ip4-config.h" +#include "nm-utils.h" -#include "nm-device-macvlan-glue.h" +#include "nmdbus-device-macvlan.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceMacvlan); -G_DEFINE_TYPE (NMDeviceMacvlan, nm_device_macvlan, NM_TYPE_DEVICE_GENERIC) +G_DEFINE_TYPE (NMDeviceMacvlan, nm_device_macvlan, NM_TYPE_DEVICE) #define NM_DEVICE_MACVLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlanPrivate)) typedef struct { - NMPlatformMacvlanProperties props; + int parent_ifindex; + gulong parent_state_id; + NMDevice *parent; + NMPlatformLnkMacvlan props; } NMDeviceMacvlanPrivate; enum { @@ -48,37 +57,147 @@ enum { PROP_PARENT, PROP_MODE, PROP_NO_PROMISC, + PROP_TAP, LAST_PROP }; -/**************************************************************/ +static int modes[][2] = { + { NM_SETTING_MACVLAN_MODE_VEPA, MACVLAN_MODE_VEPA }, + { NM_SETTING_MACVLAN_MODE_BRIDGE, MACVLAN_MODE_BRIDGE }, + { NM_SETTING_MACVLAN_MODE_PRIVATE, MACVLAN_MODE_PRIVATE }, + { NM_SETTING_MACVLAN_MODE_PASSTHRU, MACVLAN_MODE_PASSTHRU }, +}; + +static int +setting_mode_to_platform (int mode) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (modes); i++) { + if (modes[i][0] == mode) + return modes[i][1]; + } + + return 0; +} + +static int +platform_mode_to_setting (int mode) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (modes); i++) { + if (modes[i][1] == mode) + return modes[i][0]; + } + + return 0; +} + +static const char * +platform_mode_to_string (guint mode) +{ + switch (mode) { + case MACVLAN_MODE_PRIVATE: + return "private"; + case MACVLAN_MODE_VEPA: + return "vepa"; + case MACVLAN_MODE_BRIDGE: + return "bridge"; + case MACVLAN_MODE_PASSTHRU: + return "passthru"; + default: + return "unknown"; + } +} /**************************************************************/ +static void +parent_state_changed (NMDevice *parent, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason, + gpointer user_data) +{ + NMDeviceMacvlan *self = NM_DEVICE_MACVLAN (user_data); + + /* We'll react to our own carrier state notifications. Ignore the parent's. */ + if (reason == NM_DEVICE_STATE_REASON_CARRIER) + return; + + nm_device_set_unmanaged_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason); +} + +static void +nm_device_macvlan_set_parent (NMDeviceMacvlan *self, NMDevice *parent) + { + NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (self); + NMDevice *device = NM_DEVICE (self); + + if (parent == priv->parent) + return; + + if (priv->parent_state_id) + nm_clear_g_signal_handler (priv->parent, &priv->parent_state_id); + + g_clear_object (&priv->parent); + + if (parent) { + priv->parent = g_object_ref (parent); + priv->parent_state_id = g_signal_connect (priv->parent, + "state-changed", + G_CALLBACK (parent_state_changed), + device); + + /* Set parent-dependent unmanaged flag */ + nm_device_set_unmanaged_flags (device, + NM_UNMANAGED_PARENT, + !nm_device_get_managed (parent), + NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); + } + + /* Recheck availability now that the parent has changed */ + nm_device_queue_recheck_available (self, + NM_DEVICE_STATE_REASON_PARENT_CHANGED, + NM_DEVICE_STATE_REASON_PARENT_CHANGED); + g_object_notify (G_OBJECT (device), NM_DEVICE_MACVLAN_PARENT); +} + static void update_properties (NMDevice *device) { NMDeviceMacvlan *self = NM_DEVICE_MACVLAN (device); NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device); GObject *object = G_OBJECT (device); - NMPlatformMacvlanProperties props; + const NMPlatformLnkMacvlan *props; + const NMPlatformLink *plink; + NMDevice *parent = NULL; - if (!nm_platform_macvlan_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) { - _LOGW (LOGD_HW, "could not read macvlan properties"); + if (priv->props.tap) + props = nm_platform_link_get_lnk_macvtap (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink); + else + props = nm_platform_link_get_lnk_macvlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink); + + if (!props) { + _LOGW (LOGD_HW, "could not get %s properties", priv->props.tap ? "macvtap" : "macvlan"); return; } g_object_freeze_notify (object); - if (priv->props.parent_ifindex != props.parent_ifindex) - g_object_notify (object, NM_DEVICE_MACVLAN_PARENT); - if (g_strcmp0 (priv->props.mode, props.mode) != 0) + if (priv->parent_ifindex != plink->parent) { + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), plink->parent); + nm_device_macvlan_set_parent (self, parent); + } + if (priv->props.mode != props->mode) g_object_notify (object, NM_DEVICE_MACVLAN_MODE); - if (priv->props.no_promisc != props.no_promisc) + if (priv->props.no_promisc != props->no_promisc) g_object_notify (object, NM_DEVICE_MACVLAN_NO_PROMISC); - memcpy (&priv->props, &props, sizeof (NMPlatformMacvlanProperties)); + priv->parent_ifindex = plink->parent; + priv->props = *props; g_object_thaw_notify (object); } @@ -90,19 +209,370 @@ link_changed (NMDevice *device, NMPlatformLink *info) update_properties (device); } +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) +{ + const char *iface = nm_device_get_iface (device); + NMPlatformError plerr; + NMSettingMacvlan *s_macvlan; + NMPlatformLnkMacvlan lnk = { }; + int parent_ifindex; + + s_macvlan = nm_connection_get_setting_macvlan (connection); + g_assert (s_macvlan); + + parent_ifindex = nm_device_get_ifindex (parent); + g_warn_if_fail (parent_ifindex > 0); + + lnk.mode = setting_mode_to_platform (nm_setting_macvlan_get_mode (s_macvlan)); + if (!lnk.mode) { + nm_log_info (LOGD_DEVICE, "unsupported MACVLAN mode %u in connection %s", + nm_setting_macvlan_get_mode (s_macvlan), + nm_connection_get_uuid (connection)); + return FALSE; + } + lnk.no_promisc = !nm_setting_macvlan_get_promiscuous (s_macvlan); + lnk.tap = nm_setting_macvlan_get_tap (s_macvlan); + + plerr = nm_platform_link_macvlan_add (NM_PLATFORM_GET, iface, parent_ifindex, &lnk, out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create %s interface '%s' for '%s': %s", + lnk.tap ? "macvtap" : "macvlan", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; + } + + return TRUE; +} + +/******************************************************************/ + +static NMDeviceCapabilities +get_generic_capabilities (NMDevice *dev) +{ + /* We assume MACVLAN interfaces always support carrier detect */ + return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; +} + +static gboolean +bring_up (NMDevice *dev, gboolean *no_firmware) +{ + gboolean success = FALSE; + guint i = 20; + + while (i-- > 0 && !success) { + success = NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->bring_up (dev, no_firmware); + g_usleep (50); + } + + return success; +} + +/******************************************************************/ + +static gboolean +is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) +{ + if (!NM_DEVICE_MACVLAN_GET_PRIVATE (device)->parent) + return FALSE; + + return NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->is_available (device, flags); +} + +static void +notify_new_device_added (NMDevice *device, NMDevice *new_device) +{ + NMDeviceMacvlan *self = NM_DEVICE_MACVLAN (device); + NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (self); + + if (priv->parent) + return; + + if (!nm_device_is_real (device)) + return; + + update_properties (device); + + if ( priv->parent_ifindex <= 0 + || nm_device_get_ifindex (new_device) != priv->parent_ifindex) + return; + + priv->parent_ifindex = nm_device_get_ifindex (new_device); + nm_device_macvlan_set_parent (self, new_device); +} + /**************************************************************/ + +static gboolean +match_parent (NMDeviceMacvlan *self, const char *parent) +{ + NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (self); + + g_return_val_if_fail (parent != NULL, FALSE); + + if (!priv->parent) + return FALSE; + + if (nm_utils_is_uuid (parent)) { + NMActRequest *parent_req; + NMConnection *parent_connection; + + /* If the parent is a UUID, the connection matches if our parent + * device has that connection activated. + */ + + parent_req = nm_device_get_act_request (priv->parent); + if (!parent_req) + return FALSE; + + parent_connection = nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (parent_req)); + if (!parent_connection) + return FALSE; + + if (g_strcmp0 (parent, nm_connection_get_uuid (parent_connection)) != 0) + return FALSE; + } else { + /* interface name */ + if (g_strcmp0 (parent, nm_device_get_ip_iface (priv->parent)) != 0) + return FALSE; + } + + return TRUE; +} + +static gboolean +match_hwaddr (NMDevice *device, NMConnection *connection, gboolean fail_if_no_hwaddr) +{ + NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device); + NMSettingWired *s_wired; + const char *setting_mac; + const char *parent_mac; + + s_wired = nm_connection_get_setting_wired (connection); + if (!s_wired) + return !fail_if_no_hwaddr; + + setting_mac = nm_setting_wired_get_mac_address (s_wired); + if (!setting_mac) + return !fail_if_no_hwaddr; + + if (!priv->parent) + return !fail_if_no_hwaddr; + + parent_mac = nm_device_get_hw_address (priv->parent); + + return nm_utils_hwaddr_matches (setting_mac, -1, parent_mac, -1); +} + +static gboolean +check_connection_compatible (NMDevice *device, NMConnection *connection) +{ + NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device); + NMSettingMacvlan *s_macvlan; + const char *parent, *iface = NULL; + + if (!NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->check_connection_compatible (device, connection)) + return FALSE; + + s_macvlan = nm_connection_get_setting_macvlan (connection); + if (!s_macvlan) + return FALSE; + + if (nm_setting_macvlan_get_tap (s_macvlan) != priv->props.tap) + return FALSE; + + /* Before the device is realized some properties will not be set */ + if (nm_device_is_real (device)) { + + if (setting_mode_to_platform (nm_setting_macvlan_get_mode (s_macvlan)) != priv->props.mode) + return FALSE; + + if (nm_setting_macvlan_get_promiscuous (s_macvlan) == priv->props.no_promisc) + return FALSE; + + /* Check parent interface; could be an interface name or a UUID */ + parent = nm_setting_macvlan_get_parent (s_macvlan); + if (parent) { + if (!match_parent (NM_DEVICE_MACVLAN (device), parent)) + return FALSE; + } else { + /* Parent could be a MAC address in an NMSettingWired */ + if (!match_hwaddr (device, connection, TRUE)) + return FALSE; + } + } + + /* Ensure the interface name matches */ + iface = nm_connection_get_interface_name (connection); + if (iface) { + if (g_strcmp0 (nm_device_get_ip_iface (device), iface) != 0) + return FALSE; + } + + return TRUE; +} + +static gboolean +complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMSettingMacvlan *s_macvlan; + + nm_utils_complete_generic (connection, + NM_SETTING_MACVLAN_SETTING_NAME, + existing_connections, + NULL, + _("MACVLAN connection"), + NULL, + TRUE); + + s_macvlan = nm_connection_get_setting_macvlan (connection); + if (!s_macvlan) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, + "A 'macvlan' setting is required."); + return FALSE; + } + + /* If there's no MACVLAN interface, no parent, and no hardware address in the + * settings, then there's not enough information to complete the setting. + */ + if ( !nm_setting_macvlan_get_parent (s_macvlan) + && !match_hwaddr (device, connection, TRUE)) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, + "The 'macvlan' setting had no interface name, parent, or hardware address."); + return FALSE; + } + + return TRUE; +} + static void -nm_device_macvlan_init (NMDeviceMacvlan *self) +update_connection (NMDevice *device, NMConnection *connection) +{ + NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device); + NMSettingMacvlan *s_macvlan = nm_connection_get_setting_macvlan (connection); + const char *setting_parent, *new_parent; + int new_mode; + + if (!s_macvlan) { + s_macvlan = (NMSettingMacvlan *) nm_setting_macvlan_new (); + nm_connection_add_setting (connection, (NMSetting *) s_macvlan); + } + + new_mode = platform_mode_to_setting (priv->props.mode); + if (new_mode != nm_setting_macvlan_get_mode (s_macvlan)) + g_object_set (s_macvlan, NM_SETTING_MACVLAN_MODE, new_mode, NULL); + + if (priv->props.no_promisc == nm_setting_macvlan_get_promiscuous (s_macvlan)) + g_object_set (s_macvlan, NM_SETTING_MACVLAN_PROMISCUOUS, !priv->props.no_promisc, NULL); + + + if (priv->props.tap != nm_setting_macvlan_get_tap (s_macvlan)) + g_object_set (s_macvlan, NM_SETTING_MACVLAN_TAP, !!priv->props.tap, NULL); + + /* Update parent in the connection; default to parent's interface name */ + if (priv->parent) { + new_parent = nm_device_get_iface (priv->parent); + setting_parent = nm_setting_macvlan_get_parent (s_macvlan); + if (setting_parent && nm_utils_is_uuid (setting_parent)) { + NMConnection *parent_connection; + + /* Don't change a parent specified by UUID if it's still valid */ + parent_connection = nm_connection_provider_get_connection_by_uuid (nm_connection_provider_get (), setting_parent); + if (parent_connection && nm_device_check_connection_compatible (priv->parent, parent_connection)) + new_parent = NULL; + } + if (new_parent) + g_object_set (s_macvlan, NM_SETTING_MACVLAN_PARENT, new_parent, NULL); + } else + g_object_set (s_macvlan, NM_SETTING_MACVLAN_PARENT, NULL, NULL); + +} + +static NMActStageReturn +act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) { + NMActRequest *req; + NMConnection *connection; + NMSettingWired *s_wired; + const char *cloned_mac; + NMActStageReturn ret; + + g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + ret = NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->act_stage1_prepare (dev, reason); + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; + + req = nm_device_get_act_request (dev); + g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + connection = nm_act_request_get_applied_connection (req); + g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + s_wired = nm_connection_get_setting_wired (connection); + if (s_wired) { + /* Set device MAC address if the connection wants to change it */ + cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired); + if (cloned_mac) + nm_device_set_hw_addr (dev, cloned_mac, "set", LOGD_HW); + } + + return TRUE; +} + +static void +ip4_config_pre_commit (NMDevice *device, NMIP4Config *config) +{ + NMConnection *connection; + NMSettingWired *s_wired; + guint32 mtu; + + connection = nm_device_get_applied_connection (device); + g_assert (connection); + + s_wired = nm_connection_get_setting_wired (connection); + if (s_wired) { + mtu = nm_setting_wired_get_mtu (s_wired); + if (mtu) + nm_ip4_config_set_mtu (config, mtu, NM_IP_CONFIG_SOURCE_USER); + } +} + +static void +realize_start_notify (NMDevice *device, const NMPlatformLink *plink) +{ + NM_DEVICE_CLASS (nm_device_macvlan_parent_class)->realize_start_notify (device, plink); + + update_properties (device); } static void -constructed (GObject *object) +deactivate (NMDevice *device) { - update_properties (NM_DEVICE (object)); + /* Reset MAC address back to initial address */ + if (nm_device_get_initial_hw_address (device)) { + nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), + "reset", LOGD_DEVICE); + } +} - G_OBJECT_CLASS (nm_device_macvlan_parent_class)->constructed (object); +/******************************************************************/ + +static void +nm_device_macvlan_init (NMDeviceMacvlan *self) +{ } static void @@ -114,24 +584,42 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PARENT: - if (priv->props.parent_ifindex > 0) - parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->props.parent_ifindex); + if (priv->parent_ifindex > 0) + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->parent_ifindex); else parent = NULL; - g_value_set_boxed (value, parent ? nm_device_get_path (parent) : "/"); + nm_utils_g_value_set_object_path (value, parent); break; case PROP_MODE: - g_value_set_string (value, priv->props.mode); + g_value_set_string (value, platform_mode_to_string (priv->props.mode)); break; case PROP_NO_PROMISC: g_value_set_boolean (value, priv->props.no_promisc); break; + case PROP_TAP: + g_value_set_boolean (value, priv->props.tap); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_TAP: + priv->props.tap = g_value_get_boolean (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + static void nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) { @@ -140,18 +628,33 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) g_type_class_add_private (klass, sizeof (NMDeviceMacvlanPrivate)); - object_class->constructed = constructed; - object_class->get_property = get_property; + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP) + object_class->get_property = get_property; + object_class->set_property = set_property; + + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->bring_up = bring_up; + device_class->check_connection_compatible = check_connection_compatible; + device_class->complete_connection = complete_connection; + device_class->connection_type = NM_SETTING_MACVLAN_SETTING_NAME; + device_class->create_and_realize = create_and_realize; + device_class->deactivate = deactivate; + device_class->get_generic_capabilities = get_generic_capabilities; + device_class->ip4_config_pre_commit = ip4_config_pre_commit; + device_class->is_available = is_available; device_class->link_changed = link_changed; + device_class->notify_new_device_added = notify_new_device_added; + device_class->realize_start_notify = realize_start_notify; + device_class->update_connection = update_connection; /* properties */ g_object_class_install_property (object_class, PROP_PARENT, - g_param_spec_boxed (NM_DEVICE_MACVLAN_PARENT, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_DEVICE_MACVLAN_PARENT, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_MODE, @@ -167,9 +670,17 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_macvlan_object_info); + g_object_class_install_property + (object_class, PROP_TAP, + g_param_spec_boolean (NM_DEVICE_MACVLAN_TAP, "", "", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_MACVLAN_SKELETON, + NULL); } /*************************************************************/ @@ -178,17 +689,85 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) #define NM_MACVLAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MACVLAN_FACTORY, NMMacvlanFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) { + NMSettingMacvlan *s_macvlan; + NMLinkType link_type; + gboolean tap; + + if (connection) { + s_macvlan = nm_connection_get_setting_macvlan (connection); + g_assert (s_macvlan); + tap = nm_setting_macvlan_get_tap (s_macvlan); + } else { + g_assert (plink); + tap = plink->type == NM_LINK_TYPE_MACVTAP; + } + + link_type = tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_MACVLAN, - NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_IFACE, iface, NM_DEVICE_TYPE_DESC, "Macvlan", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_MACVLAN, + NM_DEVICE_LINK_TYPE, link_type, + NM_DEVICE_MACVLAN_TAP, tap, NULL); } +static const char * +get_connection_parent (NMDeviceFactory *factory, NMConnection *connection) +{ + NMSettingMacvlan *s_macvlan; + NMSettingWired *s_wired; + const char *parent = NULL; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_MACVLAN_SETTING_NAME), NULL); + + s_macvlan = nm_connection_get_setting_macvlan (connection); + g_assert (s_macvlan); + + parent = nm_setting_macvlan_get_parent (s_macvlan); + if (parent) + return parent; + + /* Try the hardware address from the MACVLAN connection's hardware setting */ + s_wired = nm_connection_get_setting_wired (connection); + if (s_wired) + return nm_setting_wired_get_mac_address (s_wired); + + return NULL; +} + +static char * +get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + NMSettingMacvlan *s_macvlan; + const char *ifname; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_MACVLAN_SETTING_NAME), NULL); + + s_macvlan = nm_connection_get_setting_macvlan (connection); + g_assert (s_macvlan); + + if (!parent_iface) + return NULL; + + ifname = nm_connection_get_interface_name (connection); + return g_strdup (ifname); +} + NM_DEVICE_FACTORY_DEFINE_INTERNAL (MACVLAN, Macvlan, macvlan, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP), - factory_iface->new_link = new_link; + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_MACVLAN_SETTING_NAME), + factory_iface->create_device = create_device; + factory_iface->get_connection_parent = get_connection_parent; + factory_iface->get_virtual_iface_name = get_virtual_iface_name; ) diff --git a/src/devices/nm-device-macvlan.h b/src/devices/nm-device-macvlan.h index 24f15437..89f670bd 100644 --- a/src/devices/nm-device-macvlan.h +++ b/src/devices/nm-device-macvlan.h @@ -21,9 +21,7 @@ #ifndef __NETWORKMANAGER_DEVICE_MACVLAN_H__ #define __NETWORKMANAGER_DEVICE_MACVLAN_H__ -#include - -#include "nm-device-generic.h" +#include "nm-device.h" G_BEGIN_DECLS @@ -37,9 +35,10 @@ G_BEGIN_DECLS #define NM_DEVICE_MACVLAN_PARENT "parent" #define NM_DEVICE_MACVLAN_MODE "mode" #define NM_DEVICE_MACVLAN_NO_PROMISC "no-promisc" +#define NM_DEVICE_MACVLAN_TAP "tap" -typedef NMDeviceGeneric NMDeviceMacvlan; -typedef NMDeviceGenericClass NMDeviceMacvlanClass; +typedef NMDevice NMDeviceMacvlan; +typedef NMDeviceClass NMDeviceMacvlanClass; GType nm_device_macvlan_get_type (void); diff --git a/src/devices/nm-device-private.h b/src/devices/nm-device-private.h index f34969ac..5010e906 100644 --- a/src/devices/nm-device-private.h +++ b/src/devices/nm-device-private.h @@ -24,9 +24,9 @@ #include "nm-device.h" -/* This file should only be used by subclasses of NMDevice */ +#include "nm-default.h" -#define NM_DEVICE_PLATFORM_DEVICE "platform-device" +/* This file should only be used by subclasses of NMDevice */ enum NMActStageReturn { NM_ACT_STAGE_RETURN_FAILURE = 0, @@ -91,7 +91,7 @@ gboolean nm_device_get_enslaved (NMDevice *device); NMDevice *nm_device_master_get_slave_by_ifindex (NMDevice *dev, int ifindex); void nm_device_master_check_slave_physical_port (NMDevice *self, NMDevice *slave, - guint64 log_domain); + NMLogDomain log_domain); void nm_device_set_carrier (NMDevice *self, gboolean carrier); @@ -106,4 +106,11 @@ void nm_device_set_wwan_ip6_config (NMDevice *device, NMIP6Config *config); gboolean nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value); +#define NM_DEVICE_CLASS_DECLARE_TYPES(klass, conn_type, ...) \ + NM_DEVICE_CLASS (klass)->connection_type = conn_type; \ + { \ + static const NMLinkType link_types[] = { __VA_ARGS__, NM_LINK_TYPE_NONE }; \ + NM_DEVICE_CLASS (klass)->link_types = link_types; \ + } + #endif /* NM_DEVICE_PRIVATE_H */ diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index 5aaff8b1..91ef8fe7 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -15,41 +15,43 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2013 Red Hat, Inc. + * Copyright 2013 - 2015 Red Hat, Inc. */ #include "config.h" #include #include +#include +#include "nm-default.h" +#include "nm-activation-request.h" #include "nm-device-tun.h" #include "nm-device-private.h" -#include "nm-dbus-manager.h" -#include "nm-logging.h" +#include "nm-ip4-config.h" #include "nm-platform.h" #include "nm-device-factory.h" +#include "nm-setting-tun.h" +#include "nm-core-internal.h" -#include "nm-device-tun-glue.h" +#include "nmdbus-device-tun.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceTun); -G_DEFINE_TYPE (NMDeviceTun, nm_device_tun, NM_TYPE_DEVICE_GENERIC) +G_DEFINE_TYPE (NMDeviceTun, nm_device_tun, NM_TYPE_DEVICE) #define NM_DEVICE_TUN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_TUN, NMDeviceTunPrivate)) typedef struct { NMPlatformTunProperties props; const char *mode; - guint delay_tun_get_properties_id; } NMDeviceTunPrivate; enum { PROP_0, PROP_OWNER, PROP_GROUP, - PROP_FLAGS, PROP_MODE, PROP_NO_PI, PROP_VNET_HDR, @@ -64,11 +66,26 @@ reload_tun_properties (NMDeviceTun *self) NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); GObject *object = G_OBJECT (self); NMPlatformTunProperties props; - - if (!nm_platform_tun_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (self)), &props)) { - _LOGD (LOGD_HW, "could not read tun properties"); - return; - } + int ifindex; + + ifindex = nm_device_get_ifindex (NM_DEVICE (self)); + if (ifindex > 0) { + if (!nm_platform_link_tun_get_properties (NM_PLATFORM_GET, ifindex, &props)) { + _LOGD (LOGD_DEVICE, "tun-properties: cannot loading tun properties from platform for ifindex %d", ifindex); + ifindex = 0; + } else if (g_strcmp0 (priv->mode, props.mode) != 0) { + /* if the mode differs, we ignore what we loaded. A NMDeviceTun cannot + * change the mode after construction. */ + _LOGD (LOGD_DEVICE, "tun-properties: loading tun properties yielded tun-mode %s%s%s, but %s%s%s expected (ifindex %d)", + NM_PRINT_FMT_QUOTE_STRING (props.mode), + NM_PRINT_FMT_QUOTE_STRING (priv->mode), + ifindex); + ifindex = 0; + } + } else + _LOGD (LOGD_DEVICE, "tun-properties: ignore loading properties due to missing ifindex"); + if (ifindex <= 0) + memset (&props, 0, sizeof (props)); g_object_freeze_notify (object); @@ -97,54 +114,251 @@ link_changed (NMDevice *device, NMPlatformLink *info) } static gboolean -delay_tun_get_properties_cb (gpointer user_data) +complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) { - NMDeviceTun *self = user_data; - NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); + NMSettingTun *s_tun; + + nm_utils_complete_generic (connection, + NM_SETTING_TUN_SETTING_NAME, + existing_connections, + NULL, + _("TUN connection"), + NULL, + TRUE); + + s_tun = nm_connection_get_setting_tun (connection); + if (!s_tun) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, + "A 'tun' setting is required."); + return FALSE; + } - priv->delay_tun_get_properties_id = 0; + return TRUE; +} - reload_tun_properties (self); +static int +tun_mode_from_string (const char *string) +{ + if (!g_strcmp0 (string, "tap")) + return NM_SETTING_TUN_MODE_TAP; + else + return NM_SETTING_TUN_MODE_TUN; +} - return G_SOURCE_REMOVE; +static void +update_connection (NMDevice *device, NMConnection *connection) +{ + NMDeviceTun *self = NM_DEVICE_TUN (device); + NMSettingTun *s_tun = nm_connection_get_setting_tun (connection); + NMPlatformTunProperties props; + NMSettingTunMode mode; + gint64 user, group; + char *str; + + if (!s_tun) { + s_tun = (NMSettingTun *) nm_setting_tun_new (); + nm_connection_add_setting (connection, (NMSetting *) s_tun); + } + + if (!nm_platform_link_tun_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) { + _LOGW (LOGD_HW, "failed to get TUN interface info while updating connection."); + return; + } + + mode = tun_mode_from_string (props.mode); + + if (mode != nm_setting_tun_get_mode (s_tun)) + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MODE, mode, NULL); + + user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); + group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1); + + if (props.owner != user) { + str = props.owner >= 0 ? g_strdup_printf ("%" G_GINT32_FORMAT, (gint32) props.owner) : NULL; + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_OWNER, str, NULL); + g_free (str); + } + + if (props.group != group) { + str = props.group >= 0 ? g_strdup_printf ("%" G_GINT32_FORMAT, (gint32) props.group) : NULL; + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_GROUP, str, NULL); + g_free (str); + } + + if ((!props.no_pi) != nm_setting_tun_get_pi (s_tun)) + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_PI, !props.no_pi, NULL); + if (props.vnet_hdr != nm_setting_tun_get_vnet_hdr (s_tun)) + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_VNET_HDR, props.vnet_hdr, NULL); + if (props.multi_queue != nm_setting_tun_get_multi_queue (s_tun)) + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MULTI_QUEUE, props.multi_queue, NULL); } -/**************************************************************/ +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) +{ + const char *iface = nm_device_get_iface (device); + NMPlatformError plerr; + NMSettingTun *s_tun; + gint64 user, group; + + s_tun = nm_connection_get_setting_tun (connection); + g_assert (s_tun); + + user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); + group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1); + + plerr = nm_platform_link_tun_add (NM_PLATFORM_GET, iface, + nm_setting_tun_get_mode (s_tun) == NM_SETTING_TUN_MODE_TAP, + user, group, + nm_setting_tun_get_pi (s_tun), + nm_setting_tun_get_vnet_hdr (s_tun), + nm_setting_tun_get_multi_queue (s_tun), + out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create TUN/TAP interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; + } + + return TRUE; +} static void -nm_device_tun_init (NMDeviceTun *self) +realize_start_notify (NMDevice *device, const NMPlatformLink *plink) { + NM_DEVICE_CLASS (nm_device_tun_parent_class)->realize_start_notify (device, plink); + reload_tun_properties (device); } -static void -constructed (GObject *object) +static gboolean +check_connection_compatible (NMDevice *device, NMConnection *connection) { - NMDeviceTun *self = NM_DEVICE_TUN (object); - gboolean properties_read; + NMDeviceTun *self = NM_DEVICE_TUN (device); NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); + NMSettingTunMode mode; + NMSettingTun *s_tun; + gint64 user, group; + + if (!NM_DEVICE_CLASS (nm_device_tun_parent_class)->check_connection_compatible (device, connection)) + return FALSE; + + s_tun = nm_connection_get_setting_tun (connection); + if (!s_tun) + return FALSE; + + if (nm_device_is_real (device)) { + mode = tun_mode_from_string (priv->mode); + if (mode != nm_setting_tun_get_mode (s_tun)) + return FALSE; + + user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); + group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1); + + if (user != priv->props.owner) + return FALSE; + if (group != priv->props.group) + return FALSE; + if (nm_setting_tun_get_pi (s_tun) == priv->props.no_pi) + return FALSE; + if (nm_setting_tun_get_vnet_hdr (s_tun) != priv->props.vnet_hdr) + return FALSE; + if (nm_setting_tun_get_multi_queue (s_tun) != priv->props.multi_queue) + return FALSE; + } - properties_read = nm_platform_tun_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (self)), &priv->props); + return TRUE; +} - G_OBJECT_CLASS (nm_device_tun_parent_class)->constructed (object); +static NMActStageReturn +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) +{ + NMDeviceTun *self = NM_DEVICE_TUN (device); + NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); + NMActRequest *req; + NMConnection *connection; + NMSettingWired *s_wired; + const char *cloned_mac; + NMActStageReturn ret; + + g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + ret = NM_DEVICE_CLASS (nm_device_tun_parent_class)->act_stage1_prepare (device, reason); + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; + + /* Nothing to do for TUN devices */ + if (g_strcmp0 (priv->mode, "tap")) + return NM_ACT_STAGE_RETURN_SUCCESS; + + req = nm_device_get_act_request (device); + g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + connection = nm_act_request_get_applied_connection (req); + g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + s_wired = nm_connection_get_setting_wired (connection); + if (s_wired) { + /* Set device MAC address if the connection wants to change it */ + cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired); + if (cloned_mac) + nm_device_set_hw_addr (device, cloned_mac, "set", LOGD_DEVICE); + } + + return NM_ACT_STAGE_RETURN_SUCCESS; +} - if (!properties_read) { - /* Error reading the tun properties. Maybe this was due to a race. Try again a bit later. */ - _LOGD (LOGD_HW, "could not read tun properties (retry)"); - priv->delay_tun_get_properties_id = g_timeout_add_seconds (1, delay_tun_get_properties_cb, self); +static void +ip4_config_pre_commit (NMDevice *device, NMIP4Config *config) +{ + NMConnection *connection; + NMSettingWired *s_wired; + guint32 mtu; + + connection = nm_device_get_applied_connection (device); + g_assert (connection); + + s_wired = nm_connection_get_setting_wired (connection); + if (s_wired) { + mtu = nm_setting_wired_get_mtu (s_wired); + if (mtu) + nm_ip4_config_set_mtu (config, mtu, NM_IP_CONFIG_SOURCE_USER); } } static void -dispose (GObject *object) +unrealize_notify (NMDevice *device) { - NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (object); + NMDeviceTun *self = NM_DEVICE_TUN (device); + NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); + GParamSpec **properties; + guint n_properties, i; - if (priv->delay_tun_get_properties_id) { - g_source_remove (priv->delay_tun_get_properties_id); - priv->delay_tun_get_properties_id = 0; - } + NM_DEVICE_CLASS (nm_device_tun_parent_class)->unrealize_notify (device); + + memset (&priv->props, 0, sizeof (NMPlatformTunProperties)); + + properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (self), &n_properties); + for (i = 0; i < n_properties; i++) + g_object_notify_by_pspec (G_OBJECT (self), properties[i]); + g_free (properties); +} - G_OBJECT_CLASS (nm_device_tun_parent_class)->dispose (object); +/**************************************************************/ + +static void +nm_device_tun_init (NMDeviceTun *self) +{ } static void @@ -214,12 +428,22 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) g_type_class_add_private (klass, sizeof (NMDeviceTunPrivate)); - object_class->constructed = constructed; + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP) + object_class->get_property = get_property; object_class->set_property = set_property; - object_class->dispose = dispose; + + device_class->connection_type = NM_SETTING_TUN_SETTING_NAME; device_class->link_changed = link_changed; + device_class->complete_connection = complete_connection; + device_class->check_connection_compatible = check_connection_compatible; + device_class->create_and_realize = create_and_realize; + device_class->realize_start_notify = realize_start_notify; + device_class->unrealize_notify = unrealize_notify; + device_class->update_connection = update_connection; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->ip4_config_pre_commit = ip4_config_pre_commit; /* properties */ g_object_class_install_property @@ -258,9 +482,9 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_tun_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_TUN_SKELETON, + NULL); } @@ -270,29 +494,49 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) #define NM_TUN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_TUN_FACTORY, NMTunFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) { - const char *mode = NULL; - - if (plink->type == NM_LINK_TYPE_TUN) - mode = "tun"; - else if (plink->type == NM_LINK_TYPE_TAP) - mode = "tap"; - else { - g_warn_if_reached (); - mode = "unknown"; + NMSettingTun *s_tun; + NMLinkType link_type = NM_LINK_TYPE_UNKNOWN; + const char *mode; + + if (plink) { + link_type = plink->type; + } else if (connection) { + s_tun = nm_connection_get_setting_tun (connection); + if (!s_tun) + return NULL; + switch (nm_setting_tun_get_mode (s_tun)) { + case NM_SETTING_TUN_MODE_TUN: + link_type = NM_LINK_TYPE_TUN; + break; + case NM_SETTING_TUN_MODE_TAP: + link_type = NM_LINK_TYPE_TAP; + break; + case NM_SETTING_TUN_MODE_UNKNOWN: + g_return_val_if_reached (NULL); + } } + g_return_val_if_fail (link_type != NM_LINK_TYPE_UNKNOWN, NULL); + mode = link_type == NM_LINK_TYPE_TUN ? "tun" : "tap"; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TUN, - NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_IFACE, iface, NM_DEVICE_TYPE_DESC, "Tun", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_TUN, + NM_DEVICE_LINK_TYPE, link_type, NM_DEVICE_TUN_MODE, mode, NULL); } NM_DEVICE_FACTORY_DEFINE_INTERNAL (TUN, Tun, tun, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP), - factory_iface->new_link = new_link; + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_TUN_SETTING_NAME), + factory_iface->create_device = create_device; ) diff --git a/src/devices/nm-device-tun.h b/src/devices/nm-device-tun.h index 393c5801..32dcfd47 100644 --- a/src/devices/nm-device-tun.h +++ b/src/devices/nm-device-tun.h @@ -21,8 +21,6 @@ #ifndef __NETWORKMANAGER_DEVICE_TUN_H__ #define __NETWORKMANAGER_DEVICE_TUN_H__ -#include - #include "nm-device-generic.h" G_BEGIN_DECLS @@ -41,8 +39,8 @@ G_BEGIN_DECLS #define NM_DEVICE_TUN_VNET_HDR "vnet-hdr" #define NM_DEVICE_TUN_MULTI_QUEUE "multi-queue" -typedef NMDeviceGeneric NMDeviceTun; -typedef NMDeviceGenericClass NMDeviceTunClass; +typedef NMDevice NMDeviceTun; +typedef NMDeviceClass NMDeviceTunClass; GType nm_device_tun_get_type (void); diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c index 04f03fbb..a1bf0d21 100644 --- a/src/devices/nm-device-veth.c +++ b/src/devices/nm-device-veth.c @@ -29,13 +29,12 @@ #include "nm-device-veth.h" #include "nm-device-private.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-manager.h" #include "nm-platform.h" -#include "nm-dbus-manager.h" #include "nm-device-factory.h" -#include "nm-device-veth-glue.h" +#include "nmdbus-device-veth.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceVeth); @@ -77,17 +76,18 @@ get_peer (NMDeviceVeth *self) { NMDeviceVethPrivate *priv = NM_DEVICE_VETH_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self), *peer = NULL; - NMPlatformVethProperties props; + int peer_ifindex; if (priv->ever_had_peer) return priv->peer; - if (!nm_platform_veth_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) { + if (!nm_platform_link_veth_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &peer_ifindex)) { _LOGW (LOGD_HW, "could not read veth properties"); return NULL; } - peer = nm_manager_get_device_by_ifindex (nm_manager_get (), props.peer); + if (peer_ifindex > 0) + peer = nm_manager_get_device_by_ifindex (nm_manager_get (), peer_ifindex); if (peer && NM_IS_DEVICE_VETH (peer)) { set_peer (self, peer); set_peer (NM_DEVICE_VETH (peer), device); @@ -137,7 +137,7 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PEER: peer = get_peer (self); - g_value_set_boxed (value, peer ? nm_device_get_path (peer) : "/"); + nm_utils_g_value_set_object_path (value, peer); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -153,6 +153,8 @@ nm_device_veth_class_init (NMDeviceVethClass *klass) g_type_class_add_private (klass, sizeof (NMDeviceVethPrivate)); + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_VETH) + object_class->get_property = get_property; object_class->dispose = dispose; @@ -161,14 +163,14 @@ nm_device_veth_class_init (NMDeviceVethClass *klass) /* properties */ g_object_class_install_property (object_class, PROP_PEER, - g_param_spec_boxed (NM_DEVICE_VETH_PEER, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_veth_object_info); + g_param_spec_string (NM_DEVICE_VETH_PEER, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_VETH_SKELETON, + NULL); } /*************************************************************/ @@ -177,17 +179,22 @@ nm_device_veth_class_init (NMDeviceVethClass *klass) #define NM_VETH_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VETH_FACTORY, NMVethFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) { return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VETH, - NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_IFACE, iface, NM_DEVICE_TYPE_DESC, "Veth", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_VETH, NULL); } NM_DEVICE_FACTORY_DEFINE_INTERNAL (VETH, Veth, veth, NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VETH), - factory_iface->new_link = new_link; + factory_iface->create_device = create_device; ) diff --git a/src/devices/nm-device-veth.h b/src/devices/nm-device-veth.h index 51e8db45..c7b8ec3a 100644 --- a/src/devices/nm-device-veth.h +++ b/src/devices/nm-device-veth.h @@ -21,8 +21,6 @@ #ifndef __NETWORKMANAGER_DEVICE_VETH_H__ #define __NETWORKMANAGER_DEVICE_VETH_H__ -#include - #include "nm-device-ethernet.h" G_BEGIN_DECLS diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index 7cce6593..f8710412 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -20,19 +20,15 @@ #include "config.h" -#include -#include - #include +#include "nm-default.h" #include "nm-device-vlan.h" #include "nm-manager.h" -#include "nm-logging.h" #include "nm-utils.h" #include "NetworkManagerUtils.h" #include "nm-device-private.h" #include "nm-enum-types.h" -#include "nm-dbus-manager.h" #include "nm-connection-provider.h" #include "nm-activation-request.h" #include "nm-ip4-config.h" @@ -40,9 +36,9 @@ #include "nm-device-factory.h" #include "nm-manager.h" #include "nm-core-internal.h" -#include "gsystem-local-alloc.h" +#include "nmp-object.h" -#include "nm-device-vlan-glue.h" +#include "nmdbus-device-vlan.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceVlan); @@ -52,12 +48,10 @@ G_DEFINE_TYPE (NMDeviceVlan, nm_device_vlan, NM_TYPE_DEVICE) #define NM_DEVICE_VLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_VLAN, NMDeviceVlanPrivate)) typedef struct { - gboolean invalid; - NMDevice *parent; - guint parent_state_id; - guint parent_hwaddr_id; - int vlan_id; + gulong parent_state_id; + gulong parent_hwaddr_id; + guint vlan_id; } NMDeviceVlanPrivate; enum { @@ -65,8 +59,6 @@ enum { PROP_PARENT, PROP_VLAN_ID, - PROP_INT_PARENT_DEVICE, - LAST_PROP }; @@ -85,7 +77,7 @@ parent_state_changed (NMDevice *parent, if (reason == NM_DEVICE_STATE_REASON_CARRIER) return; - nm_device_set_unmanaged (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason); + nm_device_set_unmanaged_flags (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason); } static void @@ -97,12 +89,13 @@ parent_hwaddr_changed (NMDevice *parent, NMConnection *connection; NMSettingWired *s_wired; const char *cloned_mac = NULL, *new_mac; + NMSettingIPConfig *s_ip6; /* Never touch assumed devices */ if (nm_device_uses_assumed_connection (self)) return; - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); if (!connection) return; @@ -118,12 +111,17 @@ parent_hwaddr_changed (NMDevice *parent, if (new_mac) { nm_device_set_hw_addr (self, nm_device_get_hw_address (parent), "set", LOGD_VLAN); + /* When changing the hw address the interface is taken down, + * removing the IPv6 configuration; reapply it. + */ + s_ip6 = nm_connection_get_setting_ip6_config (connection); + nm_device_reactivate_ip6_config (NM_DEVICE (self), s_ip6, s_ip6); } } } static void -nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent, gboolean construct) +nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent) { NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); @@ -138,7 +136,7 @@ nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent, gboolean constr if (parent) { priv->parent = g_object_ref (parent); priv->parent_state_id = g_signal_connect (priv->parent, - "state-changed", + NM_DEVICE_STATE_CHANGED, G_CALLBACK (parent_state_changed), device); @@ -146,16 +144,10 @@ nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent, gboolean constr G_CALLBACK (parent_hwaddr_changed), device); /* Set parent-dependent unmanaged flag */ - if (construct) { - nm_device_set_initial_unmanaged_flag (device, - NM_UNMANAGED_PARENT, - !nm_device_get_managed (parent)); - } else { - nm_device_set_unmanaged (device, - NM_UNMANAGED_PARENT, - !nm_device_get_managed (parent), - NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); - } + nm_device_set_unmanaged_flags (device, + NM_UNMANAGED_PARENT, + !nm_device_get_managed (parent), + NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); } /* Recheck availability now that the parent has changed */ @@ -165,6 +157,117 @@ nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent, gboolean constr g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_PARENT); } +static void +update_properties (NMDevice *device) +{ + NMDeviceVlanPrivate *priv; + const NMPlatformLink *plink = NULL; + const NMPlatformLnkVlan *plnk = NULL; + NMDevice *parent = NULL; + int ifindex; + guint vlan_id; + + g_return_if_fail (NM_IS_DEVICE_VLAN (device)); + + priv = NM_DEVICE_VLAN_GET_PRIVATE (device); + + ifindex = nm_device_get_ifindex (device); + + if (ifindex > 0) + plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, &plink); + if ( plnk + && plink->parent + && plink->parent != NM_PLATFORM_LINK_OTHER_NETNS) + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), plink->parent); + + g_object_freeze_notify ((GObject *) device); + + nm_device_vlan_set_parent ((NMDeviceVlan *) device, parent); + + vlan_id = plnk ? plnk->id : 0; + if (vlan_id != priv->vlan_id) { + priv->vlan_id = vlan_id; + g_object_notify ((GObject *) device, NM_DEVICE_VLAN_ID); + } + + g_object_thaw_notify ((GObject *) device); +} + +static void +realize_start_notify (NMDevice *device, const NMPlatformLink *plink) +{ + NM_DEVICE_CLASS (nm_device_vlan_parent_class)->realize_start_notify (device, plink); + + update_properties (device); +} + +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) +{ + NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device); + const char *iface = nm_device_get_iface (device); + NMSettingVlan *s_vlan; + int parent_ifindex; + guint vlan_id; + NMPlatformError plerr; + + s_vlan = nm_connection_get_setting_vlan (connection); + g_assert (s_vlan); + + if (!nm_device_supports_vlans (parent)) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "no support for VLANs on interface %s of type %s", + nm_device_get_iface (parent), + nm_device_get_type_desc (parent)); + return FALSE; + } + + parent_ifindex = nm_device_get_ifindex (parent); + g_warn_if_fail (parent_ifindex > 0); + + vlan_id = nm_setting_vlan_get_id (s_vlan); + + plerr = nm_platform_link_vlan_add (NM_PLATFORM_GET, + iface, + parent_ifindex, + vlan_id, + nm_setting_vlan_get_flags (s_vlan), + out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create VLAN interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; + } + + g_warn_if_fail (priv->parent == NULL); + nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent); + if (vlan_id != priv->vlan_id) { + priv->vlan_id = vlan_id; + g_object_notify ((GObject *) device, NM_DEVICE_VLAN_ID); + } + + return TRUE; +} + +static void +unrealize_notify (NMDevice *device) +{ + NM_DEVICE_CLASS (nm_device_vlan_parent_class)->unrealize_notify (device); + + NM_DEVICE_VLAN_GET_PRIVATE (device)->vlan_id = 0; + g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_ID); + nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), NULL); +} + +/******************************************************************/ + static NMDeviceCapabilities get_generic_capabilities (NMDevice *dev) { @@ -197,34 +300,29 @@ is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) return NM_DEVICE_CLASS (nm_device_vlan_parent_class)->is_available (device, flags); } -static gboolean -component_added (NMDevice *device, GObject *component) +static void +notify_new_device_added (NMDevice *device, NMDevice *new_device) { NMDeviceVlan *self = NM_DEVICE_VLAN (device); NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - NMDevice *added_device; - int parent_ifindex = -1; + const NMPlatformLink *plink; + const NMPlatformLnkVlan *plnk; if (priv->parent) - return FALSE; - - if (!NM_IS_DEVICE (component)) - return FALSE; - added_device = NM_DEVICE (component); + return; - if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, nm_device_get_ifindex (device), &parent_ifindex, NULL)) { - _LOGW (LOGD_VLAN, "failed to get VLAN interface info while checking added component."); - return FALSE; - } + if (!nm_device_is_real (device)) + return; - if ( parent_ifindex <= 0 - || nm_device_get_ifindex (added_device) != parent_ifindex) - return FALSE; + plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink); + if (!plnk) + return; - nm_device_vlan_set_parent (self, added_device, FALSE); + if ( plink->parent <= 0 + || nm_device_get_ifindex (new_device) != plink->parent) + return; - /* Don't claim parent exclusively */ - return FALSE; + nm_device_vlan_set_parent (self, new_device); } /******************************************************************/ @@ -251,7 +349,7 @@ match_parent (NMDeviceVlan *self, const char *parent) if (!parent_req) return FALSE; - parent_connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (parent_req)); + parent_connection = nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (parent_req)); if (!parent_connection) return FALSE; @@ -300,18 +398,21 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) if (!s_vlan) return FALSE; - if (nm_setting_vlan_get_id (s_vlan) != priv->vlan_id) - return FALSE; - - /* Check parent interface; could be an interface name or a UUID */ - parent = nm_setting_vlan_get_parent (s_vlan); - if (parent) { - if (!match_parent (NM_DEVICE_VLAN (device), parent)) - return FALSE; - } else { - /* Parent could be a MAC address in an NMSettingWired */ - if (!match_hwaddr (device, connection, TRUE)) + /* Before the device is realized some properties will not be set */ + if (nm_device_is_real (device)) { + if (nm_setting_vlan_get_id (s_vlan) != priv->vlan_id) return FALSE; + + /* Check parent interface; could be an interface name or a UUID */ + parent = nm_setting_vlan_get_parent (s_vlan); + if (parent) { + if (!match_parent (NM_DEVICE_VLAN (device), parent)) + return FALSE; + } else { + /* Parent could be a MAC address in an NMSettingWired */ + if (!match_hwaddr (device, connection, TRUE)) + return FALSE; + } } /* Ensure the interface name matches. If not specified we assume a match @@ -327,6 +428,18 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) return TRUE; } +static gboolean +check_connection_available (NMDevice *device, + NMConnection *connection, + NMDeviceCheckConAvailableFlags flags, + const char *specific_object) +{ + if (!nm_device_is_real (device)) + return TRUE; + + return NM_DEVICE_CLASS (nm_device_vlan_parent_class)->check_connection_available (device, connection, flags, specific_object); +} + static gboolean complete_connection (NMDevice *device, NMConnection *connection, @@ -367,54 +480,67 @@ complete_connection (NMDevice *device, static void update_connection (NMDevice *device, NMConnection *connection) { - NMDeviceVlan *self = NM_DEVICE_VLAN (device); NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device); NMSettingVlan *s_vlan = nm_connection_get_setting_vlan (connection); int ifindex = nm_device_get_ifindex (device); - int parent_ifindex = -1, vlan_id = -1; - NMDevice *parent; const char *setting_parent, *new_parent; + const NMPlatformLink *plink; + const NMPObject *polnk; + guint vlan_id; + guint vlan_flags; if (!s_vlan) { s_vlan = (NMSettingVlan *) nm_setting_vlan_new (); nm_connection_add_setting (connection, (NMSetting *) s_vlan); } - if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, ifindex, &parent_ifindex, &vlan_id)) { - _LOGW (LOGD_VLAN, "failed to get VLAN interface info while updating connection."); - return; - } + polnk = nm_platform_link_get_lnk (NM_PLATFORM_GET, ifindex, NM_LINK_TYPE_VLAN, &plink); - if (priv->vlan_id != vlan_id) { - priv->vlan_id = vlan_id; - g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_ID); - } - - if (vlan_id != nm_setting_vlan_get_id (s_vlan)) - g_object_set (s_vlan, NM_SETTING_VLAN_ID, priv->vlan_id, NULL); - - if (parent_ifindex != NM_PLATFORM_LINK_OTHER_NETNS) - parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); + if (polnk) + vlan_id = polnk->lnk_vlan.id; else - parent = NULL; - nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent, FALSE); + vlan_id = priv->vlan_id; + if (vlan_id != nm_setting_vlan_get_id (s_vlan)) + g_object_set (s_vlan, NM_SETTING_VLAN_ID, vlan_id, NULL); /* Update parent in the connection; default to parent's interface name */ - if (parent) { - new_parent = nm_device_get_iface (parent); + if ( priv->parent + && polnk + && plink->parent > 0 + && nm_device_get_ifindex (priv->parent) == plink->parent) { + new_parent = nm_device_get_iface (priv->parent); setting_parent = nm_setting_vlan_get_parent (s_vlan); if (setting_parent && nm_utils_is_uuid (setting_parent)) { NMConnection *parent_connection; /* Don't change a parent specified by UUID if it's still valid */ parent_connection = nm_connection_provider_get_connection_by_uuid (nm_connection_provider_get (), setting_parent); - if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection)) + if (parent_connection && nm_device_check_connection_compatible (priv->parent, parent_connection)) new_parent = NULL; } if (new_parent) g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, new_parent, NULL); } else g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, NULL, NULL); + + if (polnk) + vlan_flags = polnk->lnk_vlan.flags; + else + vlan_flags = NM_VLAN_FLAG_REORDER_HEADERS; + if (vlan_flags != nm_setting_vlan_get_flags (s_vlan)) + g_object_set (s_vlan, NM_SETTING_VLAN_FLAGS, (NMVlanFlags) vlan_flags, NULL); + + if (polnk) { + _nm_setting_vlan_set_priorities (s_vlan, NM_VLAN_INGRESS_MAP, + polnk->_lnk_vlan.ingress_qos_map, + polnk->_lnk_vlan.n_ingress_qos_map); + _nm_setting_vlan_set_priorities (s_vlan, NM_VLAN_EGRESS_MAP, + polnk->_lnk_vlan.egress_qos_map, + polnk->_lnk_vlan.n_egress_qos_map); + } else { + _nm_setting_vlan_set_priorities (s_vlan, NM_VLAN_INGRESS_MAP, NULL, 0); + _nm_setting_vlan_set_priorities (s_vlan, NM_VLAN_EGRESS_MAP, NULL, 0); + } } static NMActStageReturn @@ -436,7 +562,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) req = nm_device_get_act_request (dev); g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE); s_wired = nm_connection_get_setting_wired (connection); @@ -449,20 +575,29 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) s_vlan = nm_connection_get_setting_vlan (connection); if (s_vlan) { - int ifindex = nm_device_get_ifindex (dev); - int num, i; - guint32 from, to; - - num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_INGRESS_MAP); - for (i = 0; i < num; i++) { - if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_INGRESS_MAP, i, &from, &to)) - nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, from, to); - } - num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_EGRESS_MAP); - for (i = 0; i < num; i++) { - if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, i, &from, &to)) - nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, from, to); - } + gs_free NMVlanQosMapping *ingress_map = NULL; + gs_free NMVlanQosMapping *egress_map = NULL; + guint n_ingress_map = 0, n_egress_map = 0; + + _nm_setting_vlan_get_priorities (s_vlan, + NM_VLAN_INGRESS_MAP, + &ingress_map, + &n_ingress_map); + _nm_setting_vlan_get_priorities (s_vlan, + NM_VLAN_EGRESS_MAP, + &egress_map, + &n_egress_map); + + nm_platform_link_vlan_change (NM_PLATFORM_GET, + nm_device_get_ifindex (dev), + NM_VLAN_FLAGS_ALL, + nm_setting_vlan_get_flags (s_vlan), + TRUE, + ingress_map, + n_ingress_map, + TRUE, + egress_map, + n_egress_map); } return ret; @@ -475,7 +610,7 @@ ip4_config_pre_commit (NMDevice *device, NMIP4Config *config) NMSettingWired *s_wired; guint32 mtu; - connection = nm_device_get_connection (device); + connection = nm_device_get_applied_connection (device); g_assert (connection); s_wired = nm_connection_get_setting_wired (connection); @@ -501,54 +636,6 @@ nm_device_vlan_init (NMDeviceVlan * self) { } -static void -constructed (GObject *object) -{ - NMDeviceVlan *self = NM_DEVICE_VLAN (object); - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - int ifindex = nm_device_get_ifindex (NM_DEVICE (self)); - int parent_ifindex = -1, itype; - int vlan_id; - - if (G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed) - G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed (object); - - itype = nm_platform_link_get_type (NM_PLATFORM_GET, ifindex); - if (itype != NM_LINK_TYPE_VLAN) { - _LOGE (LOGD_VLAN, "failed to get VLAN interface type."); - priv->invalid = TRUE; - return; - } - - if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, ifindex, &parent_ifindex, &vlan_id)) { - _LOGW (LOGD_VLAN, "failed to get VLAN interface info."); - priv->invalid = TRUE; - return; - } - - if (parent_ifindex < 0 || vlan_id < 0) { - _LOGW (LOGD_VLAN, "VLAN parent ifindex (%d) or VLAN ID (%d) invalid.", - parent_ifindex, priv->vlan_id); - priv->invalid = TRUE; - return; - } - - if (priv->parent && parent_ifindex != nm_device_get_ip_ifindex (priv->parent)) { - _LOGW (LOGD_VLAN, "VLAN parent %s (%d) and parent ifindex %d don't match.", - nm_device_get_iface (priv->parent), - nm_device_get_ifindex (priv->parent), - parent_ifindex); - priv->invalid = TRUE; - return; - } - - priv->vlan_id = vlan_id; - _LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s (%d)", - priv->vlan_id, - priv->parent ? nm_device_get_iface (priv->parent) : "unknown", - parent_ifindex); -} - static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) @@ -557,10 +644,7 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PARENT: - g_value_set_boxed (value, priv->parent ? nm_device_get_path (priv->parent) : "/"); - break; - case PROP_INT_PARENT_DEVICE: - g_value_set_object (value, priv->parent); + nm_utils_g_value_set_object_path (value, priv->parent); break; case PROP_VLAN_ID: g_value_set_uint (value, priv->vlan_id); @@ -575,25 +659,13 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_INT_PARENT_DEVICE: - nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), g_value_get_object (value), TRUE); - break; - case PROP_VLAN_ID: - priv->vlan_id = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } static void dispose (GObject *object) { - nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), NULL, FALSE); + nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), NULL); G_OBJECT_CLASS (nm_device_vlan_parent_class)->dispose (object); } @@ -604,53 +676,47 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - parent_class->connection_type = NM_SETTING_VLAN_SETTING_NAME; + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_VLAN_SETTING_NAME, NM_LINK_TYPE_VLAN) g_type_class_add_private (object_class, sizeof (NMDeviceVlanPrivate)); /* virtual methods */ - object_class->constructed = constructed; object_class->get_property = get_property; object_class->set_property = set_property; object_class->dispose = dispose; + parent_class->create_and_realize = create_and_realize; + parent_class->realize_start_notify = realize_start_notify; + parent_class->unrealize_notify = unrealize_notify; parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->bring_up = bring_up; parent_class->act_stage1_prepare = act_stage1_prepare; parent_class->ip4_config_pre_commit = ip4_config_pre_commit; parent_class->deactivate = deactivate; parent_class->is_available = is_available; - parent_class->component_added = component_added; + parent_class->notify_new_device_added = notify_new_device_added; parent_class->check_connection_compatible = check_connection_compatible; + parent_class->check_connection_available = check_connection_available; parent_class->complete_connection = complete_connection; parent_class->update_connection = update_connection; /* properties */ g_object_class_install_property (object_class, PROP_PARENT, - g_param_spec_boxed (NM_DEVICE_VLAN_PARENT, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_DEVICE_VLAN_PARENT, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_VLAN_ID, g_param_spec_uint (NM_DEVICE_VLAN_ID, "", "", 0, 4095, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - /* Internal properties */ - g_object_class_install_property - (object_class, PROP_INT_PARENT_DEVICE, - g_param_spec_object (NM_DEVICE_VLAN_INT_PARENT_DEVICE, "", "", - NM_TYPE_DEVICE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_vlan_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_VLAN_SKELETON, + NULL); } /*************************************************************/ @@ -659,98 +725,19 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) #define NM_VLAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VLAN_FACTORY, NMVlanFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) { - int parent_ifindex = -1; - NMDevice *parent, *device; - - /* Find the parent device */ - if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, plink->ifindex, &parent_ifindex, NULL)) { - g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, - "VLAN parent ifindex unknown"); - return NULL; - } - if (parent_ifindex > 0) - parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); - else - parent = NULL; - - device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_VLAN, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_VLAN_INT_PARENT_DEVICE, parent, - NM_DEVICE_DRIVER, "8021q", - NM_DEVICE_TYPE_DESC, "VLAN", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VLAN, - NULL); - if (NM_DEVICE_VLAN_GET_PRIVATE (device)->invalid) { - g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, - "VLAN initialization failed"); - g_object_unref (device); - device = NULL; - } - - return device; -} - -static NMDevice * -create_virtual_device_for_connection (NMDeviceFactory *factory, - NMConnection *connection, - NMDevice *parent, - GError **error) -{ - NMDevice *device; - NMSettingVlan *s_vlan; - gs_free char *iface = NULL; - NMPlatformError plerr; - const NMPlatformLink *plink; - - if (!NM_IS_DEVICE (parent)) { - g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, - "VLAN interfaces must have parents"); - return NULL; - } - - s_vlan = nm_connection_get_setting_vlan (connection); - g_assert (s_vlan); - - iface = g_strdup (nm_connection_get_interface_name (connection)); - if (!iface) { - iface = nm_utils_new_vlan_name (nm_device_get_ip_iface (parent), - nm_setting_vlan_get_id (s_vlan)); - } - - plerr = nm_platform_vlan_add (NM_PLATFORM_GET, - iface, - nm_device_get_ifindex (parent), - nm_setting_vlan_get_id (s_vlan), - nm_setting_vlan_get_flags (s_vlan), - NULL); - if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { - g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create VLAN interface '%s' for '%s': %s", - iface, - nm_connection_get_id (connection), - nm_platform_error_to_string (plerr)); - return NULL; - } - plink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, iface); - - device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_VLAN, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_VLAN_INT_PARENT_DEVICE, parent, - NM_DEVICE_DRIVER, "8021q", - NM_DEVICE_TYPE_DESC, "VLAN", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VLAN, - NULL); - if (NM_DEVICE_VLAN_GET_PRIVATE (device)->invalid) { - g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, - "Failed to create VLAN interface '%s' for '%s': initialization failed", - iface, nm_connection_get_id (connection)); - g_object_unref (device); - device = NULL; - } - - return device; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VLAN, + NM_DEVICE_IFACE, iface, + NM_DEVICE_DRIVER, "8021q", + NM_DEVICE_TYPE_DESC, "VLAN", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VLAN, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_VLAN, + NULL); } static const char * @@ -807,8 +794,7 @@ get_virtual_iface_name (NMDeviceFactory *factory, NM_DEVICE_FACTORY_DEFINE_INTERNAL (VLAN, Vlan, vlan, NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VLAN) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_VLAN_SETTING_NAME), - factory_iface->new_link = new_link; - factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; + factory_iface->create_device = create_device; factory_iface->get_connection_parent = get_connection_parent; factory_iface->get_virtual_iface_name = get_virtual_iface_name; ) diff --git a/src/devices/nm-device-vlan.h b/src/devices/nm-device-vlan.h index 20fc3453..e31e171d 100644 --- a/src/devices/nm-device-vlan.h +++ b/src/devices/nm-device-vlan.h @@ -21,8 +21,6 @@ #ifndef __NETWORKMANAGER_DEVICE_VLAN_H__ #define __NETWORKMANAGER_DEVICE_VLAN_H__ -#include - #include "nm-device.h" G_BEGIN_DECLS @@ -44,9 +42,6 @@ typedef enum { #define NM_DEVICE_VLAN_PARENT "parent" #define NM_DEVICE_VLAN_ID "vlan-id" -/* Internal non-exported properties */ -#define NM_DEVICE_VLAN_INT_PARENT_DEVICE "int-parent-device" - typedef NMDevice NMDeviceVlan; typedef NMDeviceClass NMDeviceVlanClass; diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c index 186e00de..aab90539 100644 --- a/src/devices/nm-device-vxlan.c +++ b/src/devices/nm-device-vxlan.c @@ -15,49 +15,54 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2013, 2014 Red Hat, Inc. + * Copyright 2013 - 2015 Red Hat, Inc. */ #include "config.h" #include +#include "nm-default.h" #include "nm-device-vxlan.h" #include "nm-device-private.h" -#include "nm-dbus-manager.h" -#include "nm-logging.h" #include "nm-manager.h" #include "nm-platform.h" #include "nm-utils.h" #include "nm-device-factory.h" +#include "nm-setting-vxlan.h" +#include "nm-setting-wired.h" +#include "nm-connection-provider.h" +#include "nm-activation-request.h" +#include "nm-ip4-config.h" -#include "nm-device-vxlan-glue.h" +#include "nmdbus-device-vxlan.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceVxlan); -G_DEFINE_TYPE (NMDeviceVxlan, nm_device_vxlan, NM_TYPE_DEVICE_GENERIC) +G_DEFINE_TYPE (NMDeviceVxlan, nm_device_vxlan, NM_TYPE_DEVICE) #define NM_DEVICE_VXLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_VXLAN, NMDeviceVxlanPrivate)) typedef struct { - NMPlatformVxlanProperties props; + NMDevice *parent; + NMPlatformLnkVxlan props; } NMDeviceVxlanPrivate; enum { PROP_0, PROP_PARENT, PROP_ID, - PROP_GROUP, PROP_LOCAL, + PROP_GROUP, PROP_TOS, PROP_TTL, PROP_LEARNING, PROP_AGEING, PROP_LIMIT, - PROP_DST_PORT, PROP_SRC_PORT_MIN, PROP_SRC_PORT_MAX, + PROP_DST_PORT, PROP_PROXY, PROP_RSC, PROP_L2MISS, @@ -74,53 +79,60 @@ update_properties (NMDevice *device) NMDeviceVxlan *self = NM_DEVICE_VXLAN (device); NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (device); GObject *object = G_OBJECT (device); - NMPlatformVxlanProperties props; + const NMPlatformLnkVxlan *props; + NMDevice *parent; - if (!nm_platform_vxlan_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) { - _LOGW (LOGD_HW, "could not read vxlan properties"); + props = nm_platform_link_get_lnk_vxlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL); + if (!props) { + _LOGW (LOGD_HW, "could not get vxlan properties"); return; } g_object_freeze_notify (object); - if (priv->props.parent_ifindex != props.parent_ifindex) + if (priv->props.parent_ifindex != props->parent_ifindex) { + g_clear_object (&priv->parent); + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), props->parent_ifindex); + if (parent) + priv->parent = g_object_ref (parent); g_object_notify (object, NM_DEVICE_VXLAN_PARENT); - if (priv->props.id != props.id) + } + if (priv->props.id != props->id) g_object_notify (object, NM_DEVICE_VXLAN_ID); - if (priv->props.group != props.group) - g_object_notify (object, NM_DEVICE_VXLAN_GROUP); - if (priv->props.local != props.local) + if (priv->props.local != props->local) g_object_notify (object, NM_DEVICE_VXLAN_LOCAL); - if (memcmp (&priv->props.group6, &props.group6, sizeof (props.group6)) != 0) - g_object_notify (object, NM_DEVICE_VXLAN_GROUP); - if (memcmp (&priv->props.local6, &props.local6, sizeof (props.local6)) != 0) + if (memcmp (&priv->props.local6, &props->local6, sizeof (props->local6)) != 0) g_object_notify (object, NM_DEVICE_VXLAN_LOCAL); - if (priv->props.tos != props.tos) + if (priv->props.group != props->group) + g_object_notify (object, NM_DEVICE_VXLAN_GROUP); + if (memcmp (&priv->props.group6, &props->group6, sizeof (props->group6)) != 0) + g_object_notify (object, NM_DEVICE_VXLAN_GROUP); + if (priv->props.tos != props->tos) g_object_notify (object, NM_DEVICE_VXLAN_TOS); - if (priv->props.ttl != props.ttl) + if (priv->props.ttl != props->ttl) g_object_notify (object, NM_DEVICE_VXLAN_TTL); - if (priv->props.learning != props.learning) + if (priv->props.learning != props->learning) g_object_notify (object, NM_DEVICE_VXLAN_LEARNING); - if (priv->props.ageing != props.ageing) + if (priv->props.ageing != props->ageing) g_object_notify (object, NM_DEVICE_VXLAN_AGEING); - if (priv->props.limit != props.limit) + if (priv->props.limit != props->limit) g_object_notify (object, NM_DEVICE_VXLAN_LIMIT); - if (priv->props.dst_port != props.dst_port) - g_object_notify (object, NM_DEVICE_VXLAN_DST_PORT); - if (priv->props.src_port_min != props.src_port_min) + if (priv->props.src_port_min != props->src_port_min) g_object_notify (object, NM_DEVICE_VXLAN_SRC_PORT_MIN); - if (priv->props.src_port_max != props.src_port_max) + if (priv->props.src_port_max != props->src_port_max) g_object_notify (object, NM_DEVICE_VXLAN_SRC_PORT_MAX); - if (priv->props.proxy != props.proxy) + if (priv->props.dst_port != props->dst_port) + g_object_notify (object, NM_DEVICE_VXLAN_DST_PORT); + if (priv->props.proxy != props->proxy) g_object_notify (object, NM_DEVICE_VXLAN_PROXY); - if (priv->props.rsc != props.rsc) + if (priv->props.rsc != props->rsc) g_object_notify (object, NM_DEVICE_VXLAN_RSC); - if (priv->props.l2miss != props.l2miss) + if (priv->props.l2miss != props->l2miss) g_object_notify (object, NM_DEVICE_VXLAN_L2MISS); - if (priv->props.l3miss != props.l3miss) + if (priv->props.l3miss != props->l3miss) g_object_notify (object, NM_DEVICE_VXLAN_L3MISS); - memcpy (&priv->props, &props, sizeof (NMPlatformVxlanProperties)); + priv->props = *props; g_object_thaw_notify (object); } @@ -132,19 +144,424 @@ link_changed (NMDevice *device, NMPlatformLink *info) update_properties (device); } -/**************************************************************/ +static void +realize_start_notify (NMDevice *device, const NMPlatformLink *plink) +{ + g_assert (plink->type == NM_LINK_TYPE_VXLAN); + + NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->realize_start_notify (device, plink); + + update_properties (device); +} static void -nm_device_vxlan_init (NMDeviceVxlan *self) +unrealize_notify (NMDevice *device) +{ + NMDeviceVxlan *self = NM_DEVICE_VXLAN (device); + NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (self); + GParamSpec **properties; + guint n_properties, i; + + NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->unrealize_notify (device); + + memset (&priv->props, 0, sizeof (NMPlatformLnkVxlan)); + + properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (self), &n_properties); + for (i = 0; i < n_properties; i++) + g_object_notify_by_pspec (G_OBJECT (self), properties[i]); + g_free (properties); +} + +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) +{ + const char *iface = nm_device_get_iface (device); + NMPlatformError plerr; + NMPlatformLnkVxlan props = { }; + NMSettingVxlan *s_vxlan; + const char *str; + int ret; + + s_vxlan = nm_connection_get_setting_vxlan (connection); + g_assert (s_vxlan); + + if (parent) + props.parent_ifindex = nm_device_get_ifindex (parent); + + props.id = nm_setting_vxlan_get_id (s_vxlan); + + str = nm_setting_vxlan_get_local (s_vxlan); + if (str) { + ret = inet_pton (AF_INET, str, &props.local); + if (ret != 1) + ret = inet_pton (AF_INET6, str, &props.local6); + if (ret != 1) + return FALSE; + } + + str = nm_setting_vxlan_get_remote (s_vxlan); + ret = inet_pton (AF_INET, str, &props.group); + if (ret != 1) + ret = inet_pton (AF_INET6, str, &props.group6); + if (ret != 1) + return FALSE; + + props.tos = nm_setting_vxlan_get_tos (s_vxlan); + props.ttl = nm_setting_vxlan_get_ttl (s_vxlan); + props.learning = nm_setting_vxlan_get_learning (s_vxlan); + props.ageing = nm_setting_vxlan_get_ageing (s_vxlan); + props.limit = nm_setting_vxlan_get_limit (s_vxlan); + props.src_port_min = nm_setting_vxlan_get_source_port_min (s_vxlan); + props.src_port_max = nm_setting_vxlan_get_source_port_max (s_vxlan); + props.dst_port = nm_setting_vxlan_get_destination_port (s_vxlan); + props.proxy = nm_setting_vxlan_get_proxy (s_vxlan); + props.rsc = nm_setting_vxlan_get_rsc (s_vxlan); + props.l2miss = nm_setting_vxlan_get_l2_miss (s_vxlan); + props.l3miss = nm_setting_vxlan_get_l3_miss (s_vxlan); + + plerr = nm_platform_link_vxlan_add (NM_PLATFORM_GET, iface, &props, out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create VXLAN interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; + } + + return TRUE; +} + +static gboolean +match_parent (NMDeviceVxlan *self, const char *parent) +{ + NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (self); + + g_return_val_if_fail (parent != NULL, FALSE); + + if (!priv->parent) + return FALSE; + + if (nm_utils_is_uuid (parent)) { + NMActRequest *parent_req; + NMConnection *parent_connection; + + /* If the parent is a UUID, the connection matches if our parent + * device has that connection activated. + */ + parent_req = nm_device_get_act_request (priv->parent); + if (!parent_req) + return FALSE; + + parent_connection = nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (parent_req)); + if (!parent_connection) + return FALSE; + + if (g_strcmp0 (parent, nm_connection_get_uuid (parent_connection)) != 0) + return FALSE; + } else { + /* interface name */ + if (g_strcmp0 (parent, nm_device_get_ip_iface (priv->parent)) != 0) + return FALSE; + } + + return TRUE; +} + +static gboolean +address_matches (const char *str, in_addr_t addr4, struct in6_addr *addr6) +{ + in_addr_t new_addr4 = 0; + struct in6_addr new_addr6 = { }; + + if (!str) { + return addr4 == 0 + && !memcmp (addr6, &in6addr_any, sizeof (in6addr_any)); + } + + if (inet_pton (AF_INET, str, &new_addr4) == 1) + return new_addr4 == addr4; + else if (inet_pton (AF_INET6, str, &new_addr6) == 1) + return !memcmp (&new_addr6, addr6, sizeof (new_addr6)); + else + return FALSE; +} + +static gboolean +check_connection_compatible (NMDevice *device, NMConnection *connection) +{ + NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (device); + NMSettingVxlan *s_vxlan; + const char *iface, *parent; + + if (!NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->check_connection_compatible (device, connection)) + return FALSE; + + s_vxlan = nm_connection_get_setting_vxlan (connection); + if (!s_vxlan) + return FALSE; + + iface = nm_connection_get_interface_name (connection); + if (iface) { + if (g_strcmp0 (nm_device_get_ip_iface (device), iface) != 0) + return FALSE; + } + + if (nm_device_is_real (device)) { + parent = nm_setting_vxlan_get_parent (s_vxlan); + if ( parent + && !match_parent (NM_DEVICE_VXLAN (device), parent)) + return FALSE; + + if (priv->props.id != nm_setting_vxlan_get_id (s_vxlan)) + return FALSE; + + if (!address_matches (nm_setting_vxlan_get_local (s_vxlan), priv->props.local, &priv->props.local6)) + return FALSE; + + if (!address_matches (nm_setting_vxlan_get_remote (s_vxlan), priv->props.group, &priv->props.group6)) + return FALSE; + + if (priv->props.src_port_min != nm_setting_vxlan_get_source_port_min (s_vxlan)) + return FALSE; + + if (priv->props.src_port_max != nm_setting_vxlan_get_source_port_max (s_vxlan)) + return FALSE; + + if (priv->props.dst_port != nm_setting_vxlan_get_destination_port (s_vxlan)) + return FALSE; + + if (priv->props.tos != nm_setting_vxlan_get_tos (s_vxlan)) + return FALSE; + + if (priv->props.ttl != nm_setting_vxlan_get_ttl (s_vxlan)) + return FALSE; + + if (priv->props.learning != nm_setting_vxlan_get_learning (s_vxlan)) + return FALSE; + + if (priv->props.ageing != nm_setting_vxlan_get_ageing (s_vxlan)) + return FALSE; + + if (priv->props.proxy != nm_setting_vxlan_get_proxy (s_vxlan)) + return FALSE; + + if (priv->props.rsc != nm_setting_vxlan_get_rsc (s_vxlan)) + return FALSE; + + if (priv->props.l2miss != nm_setting_vxlan_get_l2_miss (s_vxlan)) + return FALSE; + + if (priv->props.l3miss != nm_setting_vxlan_get_l3_miss (s_vxlan)) + return FALSE; + } + + return TRUE; +} + +static gboolean +complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMSettingVxlan *s_vxlan; + + nm_utils_complete_generic (connection, + NM_SETTING_VXLAN_SETTING_NAME, + existing_connections, + NULL, + _("VXLAN connection"), + NULL, + TRUE); + + s_vxlan = nm_connection_get_setting_vxlan (connection); + if (!s_vxlan) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, + "A 'vxlan' setting is required."); + return FALSE; + } + + return TRUE; +} + +static void +update_connection (NMDevice *device, NMConnection *connection) +{ + NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (device); + NMSettingVxlan *s_vxlan = nm_connection_get_setting_vxlan (connection); + NMDevice *parent = NULL; + const char *setting_parent, *new_parent; + + if (!s_vxlan) { + s_vxlan = (NMSettingVxlan *) nm_setting_vxlan_new (); + nm_connection_add_setting (connection, (NMSetting *) s_vxlan); + } + + if (priv->props.id != nm_setting_vxlan_get_id (s_vxlan)) + g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_ID, priv->props.id, NULL); + + if (priv->props.parent_ifindex != NM_PLATFORM_LINK_OTHER_NETNS) + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->props.parent_ifindex); + + /* Update parent in the connection; default to parent's interface name */ + if (parent) { + new_parent = nm_device_get_iface (parent); + setting_parent = nm_setting_vxlan_get_parent (s_vxlan); + if (setting_parent && nm_utils_is_uuid (setting_parent)) { + NMConnection *parent_connection; + + /* Don't change a parent specified by UUID if it's still valid */ + parent_connection = nm_connection_provider_get_connection_by_uuid (nm_connection_provider_get (), + setting_parent); + if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection)) + new_parent = NULL; + } + if (new_parent) + g_object_set (s_vxlan, NM_SETTING_VXLAN_PARENT, new_parent, NULL); + } else + g_object_set (s_vxlan, NM_SETTING_VXLAN_PARENT, NULL, NULL); + + if (!address_matches (nm_setting_vxlan_get_remote (s_vxlan), priv->props.group, &priv->props.group6)) { + if (priv->props.group) { + g_object_set (s_vxlan, NM_SETTING_VXLAN_REMOTE, + nm_utils_inet4_ntop (priv->props.group, NULL), + NULL); + } else { + g_object_set (s_vxlan, NM_SETTING_VXLAN_REMOTE, + nm_utils_inet6_ntop (&priv->props.group6, NULL), + NULL); + } + } + + if (!address_matches (nm_setting_vxlan_get_local (s_vxlan), priv->props.local, &priv->props.local6)) { + if (priv->props.local) { + g_object_set (s_vxlan, NM_SETTING_VXLAN_LOCAL, + nm_utils_inet4_ntop (priv->props.local, NULL), + NULL); + } else if (memcmp (&priv->props.local6, &in6addr_any, sizeof (in6addr_any))) { + g_object_set (s_vxlan, NM_SETTING_VXLAN_LOCAL, + nm_utils_inet6_ntop (&priv->props.local6, NULL), + NULL); + } + } + + if (priv->props.src_port_min != nm_setting_vxlan_get_source_port_min (s_vxlan)) { + g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_SOURCE_PORT_MIN, + priv->props.src_port_min, NULL); + } + + if (priv->props.src_port_max != nm_setting_vxlan_get_source_port_max (s_vxlan)) { + g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_SOURCE_PORT_MAX, + priv->props.src_port_max, NULL); + } + + if (priv->props.dst_port != nm_setting_vxlan_get_destination_port (s_vxlan)) { + g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_DESTINATION_PORT, + priv->props.dst_port, NULL); + } + + if (priv->props.tos != nm_setting_vxlan_get_tos (s_vxlan)) { + g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_TOS, + priv->props.tos, NULL); + } + + if (priv->props.ttl != nm_setting_vxlan_get_ttl (s_vxlan)) { + g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_TTL, + priv->props.ttl, NULL); + } + + if (priv->props.learning != nm_setting_vxlan_get_learning (s_vxlan)) { + g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_LEARNING, + priv->props.learning, NULL); + } + + if (priv->props.ageing != nm_setting_vxlan_get_ageing (s_vxlan)) { + g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_AGEING, + priv->props.ageing, NULL); + } + + if (priv->props.proxy != nm_setting_vxlan_get_proxy (s_vxlan)) { + g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_PROXY, + priv->props.proxy, NULL); + } + + if (priv->props.rsc != nm_setting_vxlan_get_rsc (s_vxlan)) { + g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_RSC, + priv->props.rsc, NULL); + } + + if (priv->props.l2miss != nm_setting_vxlan_get_l2_miss (s_vxlan)) { + g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_L2_MISS, + priv->props.l2miss, NULL); + } + + if (priv->props.l3miss != nm_setting_vxlan_get_l3_miss (s_vxlan)) { + g_object_set (G_OBJECT (s_vxlan), NM_SETTING_VXLAN_L3_MISS, + priv->props.l3miss, NULL); + } +} + +static NMActStageReturn +act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) { + NMActRequest *req; + NMConnection *connection; + NMSettingWired *s_wired; + const char *cloned_mac; + NMActStageReturn ret; + + g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + ret = NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->act_stage1_prepare (device, reason); + if (ret != NM_ACT_STAGE_RETURN_SUCCESS) + return ret; + + req = nm_device_get_act_request (device); + g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + connection = nm_act_request_get_applied_connection (req); + g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE); + + s_wired = nm_connection_get_setting_wired (connection); + if (s_wired) { + /* Set device MAC address if the connection wants to change it */ + cloned_mac = nm_setting_wired_get_cloned_mac_address (s_wired); + if (cloned_mac) + nm_device_set_hw_addr (device, cloned_mac, "set", LOGD_DEVICE); + } + + return NM_ACT_STAGE_RETURN_SUCCESS; } static void -constructed (GObject *object) +ip4_config_pre_commit (NMDevice *device, NMIP4Config *config) { - update_properties (NM_DEVICE (object)); + NMConnection *connection; + NMSettingWired *s_wired; + guint32 mtu; + + connection = nm_device_get_applied_connection (device); + g_assert (connection); + + s_wired = nm_connection_get_setting_wired (connection); + if (s_wired) { + mtu = nm_setting_wired_get_mtu (s_wired); + if (mtu) + nm_ip4_config_set_mtu (config, mtu, NM_IP_CONFIG_SOURCE_USER); + } +} + +/**************************************************************/ - G_OBJECT_CLASS (nm_device_vxlan_parent_class)->constructed (object); +static void +nm_device_vxlan_init (NMDeviceVxlan *self) +{ } static void @@ -157,7 +574,7 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PARENT: parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->props.parent_ifindex); - g_value_set_boxed (value, parent ? nm_device_get_path (parent) : "/"); + nm_utils_g_value_set_object_path (value, parent); break; case PROP_ID: g_value_set_uint (value, priv->props.id); @@ -216,6 +633,15 @@ get_property (GObject *object, guint prop_id, } } +static void +dispose (GObject *object) +{ + NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (object); + + g_clear_object (&priv->parent); + G_OBJECT_CLASS (nm_device_vxlan_parent_class)->dispose (object); +} + static void nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) { @@ -224,18 +650,29 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) g_type_class_add_private (klass, sizeof (NMDeviceVxlanPrivate)); - object_class->constructed = constructed; + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_VXLAN) + object_class->get_property = get_property; + object_class->dispose = dispose; device_class->link_changed = link_changed; + device_class->realize_start_notify = realize_start_notify; + device_class->unrealize_notify = unrealize_notify; + device_class->connection_type = NM_SETTING_VXLAN_SETTING_NAME; + device_class->create_and_realize = create_and_realize; + device_class->check_connection_compatible = check_connection_compatible; + device_class->complete_connection = complete_connection; + device_class->update_connection = update_connection; + device_class->act_stage1_prepare = act_stage1_prepare; + device_class->ip4_config_pre_commit = ip4_config_pre_commit; /* properties */ g_object_class_install_property (object_class, PROP_PARENT, - g_param_spec_boxed (NM_DEVICE_VXLAN_PARENT, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_DEVICE_VXLAN_PARENT, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_ID, @@ -245,15 +682,15 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) G_PARAM_STATIC_STRINGS)); g_object_class_install_property - (object_class, PROP_GROUP, - g_param_spec_string (NM_DEVICE_VXLAN_GROUP, "", "", + (object_class, PROP_LOCAL, + g_param_spec_string (NM_DEVICE_VXLAN_LOCAL, "", "", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property - (object_class, PROP_LOCAL, - g_param_spec_string (NM_DEVICE_VXLAN_LOCAL, "", "", + (object_class, PROP_GROUP, + g_param_spec_string (NM_DEVICE_VXLAN_GROUP, "", "", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -294,22 +731,22 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) G_PARAM_STATIC_STRINGS)); g_object_class_install_property - (object_class, PROP_DST_PORT, - g_param_spec_uint (NM_DEVICE_VXLAN_DST_PORT, "", "", + (object_class, PROP_SRC_PORT_MIN, + g_param_spec_uint (NM_DEVICE_VXLAN_SRC_PORT_MIN, "", "", 0, 65535, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property - (object_class, PROP_SRC_PORT_MIN, - g_param_spec_uint (NM_DEVICE_VXLAN_SRC_PORT_MIN, "", "", + (object_class, PROP_SRC_PORT_MAX, + g_param_spec_uint (NM_DEVICE_VXLAN_SRC_PORT_MAX, "", "", 0, 65535, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property - (object_class, PROP_SRC_PORT_MAX, - g_param_spec_uint (NM_DEVICE_VXLAN_SRC_PORT_MAX, "", "", + (object_class, PROP_DST_PORT, + g_param_spec_uint (NM_DEVICE_VXLAN_DST_PORT, "", "", 0, 65535, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -342,9 +779,9 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_vxlan_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_VXLAN_SKELETON, + NULL); } /*************************************************************/ @@ -353,17 +790,58 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) #define NM_VXLAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VXLAN_FACTORY, NMVxlanFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) { return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VXLAN, - NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_IFACE, iface, NM_DEVICE_TYPE_DESC, "Vxlan", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VXLAN, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_VXLAN, NULL); } +static const char * +get_connection_parent (NMDeviceFactory *factory, NMConnection *connection) +{ + NMSettingVxlan *s_vxlan; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_VXLAN_SETTING_NAME), NULL); + + s_vxlan = nm_connection_get_setting_vxlan (connection); + g_assert (s_vxlan); + + return nm_setting_vxlan_get_parent (s_vxlan); +} + +static char * +get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + const char *ifname; + NMSettingVxlan *s_vxlan; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_VXLAN_SETTING_NAME), NULL); + + s_vxlan = nm_connection_get_setting_vxlan (connection); + g_assert (s_vxlan); + + if (nm_setting_vxlan_get_parent (s_vxlan) && !parent_iface) + return NULL; + + ifname = nm_connection_get_interface_name (connection); + return g_strdup (ifname); +} + NM_DEVICE_FACTORY_DEFINE_INTERNAL (VXLAN, Vxlan, vxlan, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VXLAN), - factory_iface->new_link = new_link; + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VXLAN) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_VXLAN_SETTING_NAME), + factory_iface->create_device = create_device; + factory_iface->get_connection_parent = get_connection_parent; + factory_iface->get_virtual_iface_name = get_virtual_iface_name; ) diff --git a/src/devices/nm-device-vxlan.h b/src/devices/nm-device-vxlan.h index cc6081e6..7de04a12 100644 --- a/src/devices/nm-device-vxlan.h +++ b/src/devices/nm-device-vxlan.h @@ -21,8 +21,6 @@ #ifndef __NETWORKMANAGER_DEVICE_VXLAN_H__ #define __NETWORKMANAGER_DEVICE_VXLAN_H__ -#include - #include "nm-device-generic.h" G_BEGIN_DECLS @@ -51,8 +49,8 @@ G_BEGIN_DECLS #define NM_DEVICE_VXLAN_L2MISS "l2miss" #define NM_DEVICE_VXLAN_L3MISS "l3miss" -typedef NMDeviceGeneric NMDeviceVxlan; -typedef NMDeviceGenericClass NMDeviceVxlanClass; +typedef NMDevice NMDeviceVxlan; +typedef NMDeviceClass NMDeviceVxlanClass; GType nm_device_vxlan_get_type (void); diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index bb39ca55..93782a45 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -21,9 +21,6 @@ #include "config.h" -#include -#include -#include #include #include #include @@ -35,9 +32,9 @@ #include #include #include +#include -#include "gsystem-local-alloc.h" -#include "nm-glib-compat.h" +#include "nm-default.h" #include "nm-device.h" #include "nm-device-private.h" #include "NetworkManagerUtils.h" @@ -46,8 +43,6 @@ #include "nm-rdisc.h" #include "nm-lndp-rdisc.h" #include "nm-dhcp-manager.h" -#include "nm-dbus-manager.h" -#include "nm-logging.h" #include "nm-activation-request.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" @@ -56,35 +51,35 @@ #include "nm-dhcp6-config.h" #include "nm-rfkill-manager.h" #include "nm-firewall-manager.h" -#include "nm-properties-changed-signal.h" #include "nm-enum-types.h" #include "nm-settings-connection.h" #include "nm-connection-provider.h" #include "nm-auth-utils.h" -#include "nm-dbus-glib-types.h" #include "nm-dispatcher.h" #include "nm-config.h" #include "nm-dns-manager.h" #include "nm-core-internal.h" #include "nm-default-route-manager.h" #include "nm-route-manager.h" +#include "nm-lldp-listener.h" +#include "sd-ipv4ll.h" +#include "nm-audit-manager.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF (NMDevice); -static void impl_device_disconnect (NMDevice *self, DBusGMethodInvocation *context); -static void impl_device_delete (NMDevice *self, DBusGMethodInvocation *context); +#include "nmdbus-device.h" + static void ip_check_ping_watch_cb (GPid pid, gint status, gpointer user_data); static gboolean ip_config_valid (NMDeviceState state); -static void nm_device_update_metered (NMDevice *self); static NMActStageReturn dhcp4_start (NMDevice *self, NMConnection *connection, NMDeviceStateReason *reason); static gboolean dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason); +static void nm_device_start_ip_check (NMDevice *self); +static void realize_start_setup (NMDevice *self, const NMPlatformLink *plink); -#include "nm-device-glue.h" - -G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, G_TYPE_OBJECT) +G_DEFINE_ABSTRACT_TYPE (NMDevice, nm_device, NM_TYPE_EXPORTED_OBJECT) -#define NM_DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE, NMDevicePrivate)) +#define NM_DEVICE_GET_PRIVATE(o) ((o)->priv) enum { STATE_CHANGED, @@ -95,14 +90,12 @@ enum { REMOVED, RECHECK_AUTO_ACTIVATE, RECHECK_ASSUME, - LINK_INITIALIZED, LAST_SIGNAL, }; static guint signals[LAST_SIGNAL] = { 0 }; enum { PROP_0, - PROP_PLATFORM_DEVICE, PROP_UDI, PROP_IFACE, PROP_IP_IFACE, @@ -121,9 +114,11 @@ enum { PROP_STATE_REASON, PROP_ACTIVE_CONNECTION, PROP_DEVICE_TYPE, + PROP_LINK_TYPE, PROP_MANAGED, PROP_AUTOCONNECT, PROP_FIRMWARE_MISSING, + PROP_NM_PLUGIN_MISSING, PROP_TYPE_DESC, PROP_RFKILL_TYPE, PROP_IFINDEX, @@ -134,15 +129,27 @@ enum { PROP_HW_ADDRESS, PROP_HAS_PENDING_ACTION, PROP_METERED, + PROP_LLDP_NEIGHBORS, + PROP_REAL, + PROP_SLAVES, LAST_PROP }; +#define DEFAULT_AUTOCONNECT TRUE + /***********************************************************/ #define PENDING_ACTION_DHCP4 "dhcp4" #define PENDING_ACTION_DHCP6 "dhcp6" #define PENDING_ACTION_AUTOCONF6 "autoconf6" +typedef void (*ActivationHandleFunc) (NMDevice *self); + +typedef struct { + ActivationHandleFunc func; + guint id; +} ActivationHandleData; + typedef enum { CLEANUP_TYPE_DECONFIGURE, CLEANUP_TYPE_KEEP, @@ -165,13 +172,13 @@ typedef struct { typedef struct { NMDevice *slave; - gboolean enslaved; + gboolean slave_is_enslaved; gboolean configure; - guint watch_id; + gulong watch_id; } SlaveInfo; typedef struct { - guint log_domain; + NMLogDomain log_domain; guint timeout; guint watch; GPid pid; @@ -186,7 +193,7 @@ typedef struct { int ifindex; } DeleteOnDeactivateData; -typedef struct { +typedef struct _NMDevicePrivate { gboolean in_state_changed; gboolean initialized; gboolean platform_link_initialized; @@ -200,22 +207,25 @@ typedef struct { guint queued_ip4_config_id; guint queued_ip6_config_id; GSList *pending_actions; + GSList *dad6_failed_addrs; char * udi; - char * path; char * iface; /* may change, could be renamed by user */ int ifindex; + gboolean real; char * ip_iface; int ip_ifindex; NMDeviceType type; char * type_desc; char * type_description; + NMLinkType link_type; NMDeviceCapabilities capabilities; char * driver; char * driver_version; char * firmware_version; RfKillType rfkill_type; gboolean firmware_missing; + gboolean nm_plugin_missing; GHashTable * available_connections; char * hw_addr; guint hw_addr_len; @@ -224,6 +234,7 @@ typedef struct { char * physical_port_id; guint dev_id; + gboolean managed_touched_by_user; NMUnmanagedFlags unmanaged_flags; gboolean is_nm_owned; /* whether the device is a device owned and created by NM */ DeleteOnDeactivateData *delete_on_deactivate_data; /* data for scheduled cleanup when deleting link (g_idle_add) */ @@ -235,13 +246,11 @@ typedef struct { NMActRequest * queued_act_request; gboolean queued_act_request_is_waiting_for_carrier; NMActRequest * act_request; - guint act_source_id; - gpointer act_source_func; - guint act_source6_id; - gpointer act_source6_func; + ActivationHandleData act_handle4; /* for layer2 and IPv4. */ + ActivationHandleData act_handle6; guint recheck_assume_id; struct { - guint call_id; + guint call_id; NMDeviceStateReason available_reason; NMDeviceStateReason unavailable_reason; } recheck_available; @@ -272,6 +281,7 @@ typedef struct { NMIP4Config * dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */ NMIP4Config * ext_ip4_config; /* Stuff added outside NM */ NMIP4Config * wwan_ip4_config; /* WWAN configuration */ + GSList * vpn4_configs; /* VPNs which use this device */ struct { gboolean v4_has; gboolean v4_is_assumed; @@ -289,7 +299,6 @@ typedef struct { gulong dhcp4_state_sigid; NMDhcp4Config * dhcp4_config; guint dhcp4_restart_id; - NMIP4Config * vpn4_config; /* routes added by a VPN which uses this device */ guint arp_round2_id; PingInfo gw_ping; @@ -299,20 +308,20 @@ typedef struct { gulong dnsmasq_state_id; /* Firewall */ - NMFirewallPendingCall fw_call; + gboolean fw_ready; + NMFirewallManagerCallId fw_call; - /* avahi-autoipd stuff */ - GPid aipd_pid; - guint aipd_watch; - guint aipd_timeout; + /* IPv4LL stuff */ + sd_ipv4ll * ipv4ll; + guint ipv4ll_timeout; /* IP6 configuration info */ NMIP6Config * ip6_config; IpState ip6_state; NMIP6Config * con_ip6_config; /* config from the setting */ - NMIP6Config * vpn6_config; /* routes added by a VPN which uses this device */ NMIP6Config * wwan_ip6_config; NMIP6Config * ext_ip6_config; /* Stuff added outside NM */ + GSList * vpn6_configs; /* VPNs which use this device */ gboolean nm_ipv6ll; /* TRUE if NM handles the device's IPv6LL address */ guint32 ip6_mtu; @@ -324,6 +333,7 @@ typedef struct { NMIP6Config * ac_ip6_config; guint linklocal6_timeout_id; + guint8 linklocal6_dad_counter; GHashTable * ip6_saved_properties; @@ -342,9 +352,9 @@ typedef struct { /* master interface for bridge/bond/team slave */ NMDevice * master; - gboolean enslaved; + gboolean is_enslaved; gboolean master_ready_handled; - guint master_ready_id; + gulong master_ready_id; /* slave management */ gboolean is_master; @@ -353,6 +363,9 @@ typedef struct { NMMetered metered; NMConnectionProvider *con_provider; + NMLldpListener *lldp_listener; + + guint check_delete_unrealized_id; } NMDevicePrivate; static gboolean nm_device_set_ip4_config (NMDevice *self, @@ -372,7 +385,7 @@ static gboolean nm_device_set_ip6_config (NMDevice *self, gboolean routes_full_sync, NMDeviceStateReason *reason); -static gboolean nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure); +static void nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure); static void nm_device_slave_notify_enslave (NMDevice *self, gboolean success); static void nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason); @@ -384,12 +397,20 @@ static void _carrier_wait_check_queued_act_request (NMDevice *self); static gboolean nm_device_get_default_unmanaged (NMDevice *self); +static const char *_activation_func_to_string (ActivationHandleFunc func); +static void activation_source_handle_cb (NMDevice *self, int family); + static void _set_state_full (NMDevice *self, NMDeviceState state, NMDeviceStateReason reason, gboolean quitting); -static void nm_device_update_hw_address (NMDevice *self); +static gboolean queued_ip4_config_change (gpointer user_data); +static gboolean queued_ip6_config_change (gpointer user_data); + +static void _set_unmanaged_flags (NMDevice *self, + NMUnmanagedFlags flags, + gboolean unmanaged); /***********************************************************/ @@ -425,7 +446,7 @@ state_to_string (NMDeviceState state) return queued_state_to_string (state) + strlen (QUEUED_PREFIX); } -static const char *reason_table[] = { +NM_UTILS_STRING_LOOKUP_TABLE_DEFINE_STATIC (_reason_to_string, NMDeviceStateReason, NULL, [NM_DEVICE_STATE_REASON_UNKNOWN] = "unknown", [NM_DEVICE_STATE_REASON_NONE] = "none", [NM_DEVICE_STATE_REASON_NOW_MANAGED] = "managed", @@ -489,15 +510,10 @@ static const char *reason_table[] = { [NM_DEVICE_STATE_REASON_NEW_ACTIVATION] = "new-activation", [NM_DEVICE_STATE_REASON_PARENT_CHANGED] = "parent-changed", [NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED] = "parent-managed-changed", -}; +); -static const char * -reason_to_string (NMDeviceStateReason reason) -{ - if ((gsize) reason < G_N_ELEMENTS (reason_table)) - return reason_table[reason]; - return reason_table[NM_DEVICE_STATE_REASON_UNKNOWN]; -} +#define reason_to_string(reason) \ + NM_UTILS_STRING_LOOKUP_TABLE (_reason_to_string, reason) /***********************************************************/ @@ -521,30 +537,6 @@ nm_device_has_capability (NMDevice *self, NMDeviceCapabilities caps) /***********************************************************/ -void -nm_device_dbus_export (NMDevice *self) -{ - static guint32 devcount = 0; - NMDevicePrivate *priv; - - g_return_if_fail (NM_IS_DEVICE (self)); - - priv = NM_DEVICE_GET_PRIVATE (self); - g_return_if_fail (priv->path == NULL); - - priv->path = g_strdup_printf ("/org/freedesktop/NetworkManager/Devices/%d", devcount++); - _LOGD (LOGD_DEVICE, "exported as %s", priv->path); - nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->path, self); -} - -const char * -nm_device_get_path (NMDevice *self) -{ - g_return_val_if_fail (self != NULL, NULL); - - return NM_DEVICE_GET_PRIVATE (self)->path; -} - const char * nm_device_get_udi (NMDevice *self) { @@ -564,17 +556,40 @@ nm_device_get_iface (NMDevice *self) int nm_device_get_ifindex (NMDevice *self) { - g_return_val_if_fail (self != NULL, 0); + g_return_val_if_fail (NM_IS_DEVICE (self), 0); return NM_DEVICE_GET_PRIVATE (self)->ifindex; } +/** + * nm_device_is_software: + * @self: the #NMDevice + * + * Indicates if the device is a software-based virtual device without + * backing hardware, which can be added and removed programmatically. + * + * Returns: %TRUE if the device is a software-based device + */ gboolean nm_device_is_software (NMDevice *self) { return NM_FLAGS_HAS (NM_DEVICE_GET_PRIVATE (self)->capabilities, NM_DEVICE_CAP_IS_SOFTWARE); } +/** + * nm_device_is_real: + * @self: the #NMDevice + * + * Returns: %TRUE if the device exists, %FALSE if the device is a placeholder + */ +gboolean +nm_device_is_real (NMDevice *self) +{ + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + + return NM_DEVICE_GET_PRIVATE (self)->real; +} + const char * nm_device_get_ip_iface (NMDevice *self) { @@ -701,13 +716,21 @@ nm_device_get_device_type (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->type; } +NMLinkType +nm_device_get_link_type (NMDevice *self) +{ + g_return_val_if_fail (NM_IS_DEVICE (self), NM_LINK_TYPE_UNKNOWN); + + return NM_DEVICE_GET_PRIVATE (self)->link_type; +} + /** * nm_device_get_metered: * @setting: the #NMDevice * * Returns: the #NMDevice:metered property of the device. * - * Since: 1.0.6 + * Since: 1.2 **/ NMMetered nm_device_get_metered (NMDevice *self) @@ -762,12 +785,20 @@ nm_device_get_priority (NMDevice *self) return 350; case NM_DEVICE_TYPE_VLAN: return 400; + case NM_DEVICE_TYPE_MACVLAN: + return 410; case NM_DEVICE_TYPE_BRIDGE: return 425; + case NM_DEVICE_TYPE_TUN: + return 450; + case NM_DEVICE_TYPE_VXLAN: + return 500; case NM_DEVICE_TYPE_WIFI: return 600; case NM_DEVICE_TYPE_OLPC_MESH: return 650; + case NM_DEVICE_TYPE_IP_TUNNEL: + return 675; case NM_DEVICE_TYPE_MODEM: return 700; case NM_DEVICE_TYPE_BT: @@ -795,7 +826,7 @@ _get_ipx_route_metric (NMDevice *self, g_return_val_if_fail (NM_IS_DEVICE (self), G_MAXUINT32); - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); if (connection) { s_ip = is_v4 ? nm_connection_get_setting_ip4_config (connection) @@ -923,12 +954,31 @@ nm_device_get_act_request (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->act_request; } +NMSettingsConnection * +nm_device_get_settings_connection (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + return priv->act_request ? nm_act_request_get_settings_connection (priv->act_request) : NULL; +} + NMConnection * -nm_device_get_connection (NMDevice *self) +nm_device_get_applied_connection (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + return priv->act_request ? nm_act_request_get_applied_connection (priv->act_request) : NULL; +} + +gboolean +nm_device_has_unmodified_applied_connection (NMDevice *self, NMSettingCompareFlags compare_flags) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - return priv->act_request ? nm_act_request_get_connection (priv->act_request) : NULL; + if (!priv->act_request) + return FALSE; + + return nm_active_connection_has_unmodified_applied_connection ((NMActiveConnection *) priv->act_request, compare_flags); } RfKillType @@ -951,13 +1001,13 @@ static gboolean nm_device_uses_generated_assumed_connection (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; + NMSettingsConnection *connection; if ( priv->act_request && nm_active_connection_get_assumed (NM_ACTIVE_CONNECTION (priv->act_request))) { - connection = nm_act_request_get_connection (priv->act_request); + connection = nm_act_request_get_settings_connection (priv->act_request); if ( connection - && nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) + && nm_settings_connection_get_nm_generated_assumed (connection)) return TRUE; } return FALSE; @@ -989,17 +1039,8 @@ find_slave_info (NMDevice *self, NMDevice *slave) return NULL; } -static void -free_slave_info (SlaveInfo *info) -{ - g_signal_handler_disconnect (info->slave, info->watch_id); - g_clear_object (&info->slave); - memset (info, 0, sizeof (*info)); - g_free (info); -} - /** - * nm_device_enslave_slave: + * nm_device_master_enslave_slave: * @self: the master device * @slave: the slave device to enslave * @connection: (allow-none): the slave device's connection @@ -1011,7 +1052,7 @@ free_slave_info (SlaveInfo *info) * other devices. */ static gboolean -nm_device_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *connection) +nm_device_master_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *connection) { SlaveInfo *info; gboolean success = FALSE; @@ -1025,7 +1066,7 @@ nm_device_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *connecti if (!info) return FALSE; - if (info->enslaved) + if (info->slave_is_enslaved) success = TRUE; else { configure = (info->configure && connection != NULL); @@ -1033,7 +1074,7 @@ nm_device_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *connecti g_return_val_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); success = NM_DEVICE_GET_CLASS (self)->enslave_slave (self, slave, connection, configure); - info->enslaved = success; + info->slave_is_enslaved = success; } nm_device_slave_notify_enslave (info->slave, success); @@ -1059,7 +1100,7 @@ nm_device_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *connecti } /** - * nm_device_release_one_slave: + * nm_device_master_release_one_slave: * @self: the master device * @slave: the slave device to release * @configure: whether @self needs to actually release @slave @@ -1068,49 +1109,55 @@ nm_device_enslave_slave (NMDevice *self, NMDevice *slave, NMConnection *connecti * If @self is capable of enslaving other devices (ie it's a bridge, bond, team, * etc) then this function releases the previously enslaved @slave and/or * updates the state of @self and @slave to reflect its release. - * - * Returns: %TRUE on success, %FALSE on failure, if this device cannot enslave - * other devices, or if @slave was never enslaved. */ -static gboolean -nm_device_release_one_slave (NMDevice *self, NMDevice *slave, gboolean configure, NMDeviceStateReason reason) +static void +nm_device_master_release_one_slave (NMDevice *self, NMDevice *slave, gboolean configure, NMDeviceStateReason reason) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv; + NMDevicePrivate *slave_priv; SlaveInfo *info; - gboolean success = FALSE; + gs_unref_object NMDevice *self_free = NULL; - g_return_val_if_fail (slave != NULL, FALSE); - g_return_val_if_fail (NM_DEVICE_GET_CLASS (self)->release_slave != NULL, FALSE); + g_return_if_fail (NM_DEVICE (self)); + g_return_if_fail (NM_DEVICE (slave)); + g_return_if_fail (NM_DEVICE_GET_CLASS (self)->release_slave != NULL); info = find_slave_info (self, slave); + + _LOGt (LOGD_CORE, "master: release one slave %p/%s%s", slave, nm_device_get_iface (slave), + !info ? " (not registered)" : ""); + if (!info) - return FALSE; - priv->slaves = g_slist_remove (priv->slaves, info); + g_return_if_reached (); - if (info->enslaved) { - success = NM_DEVICE_GET_CLASS (self)->release_slave (self, slave, configure); - /* The release_slave() implementation logs success/failure (in the - * correct device-specific log domain), so we don't have to do anything. - */ - } + priv = NM_DEVICE_GET_PRIVATE (self); + slave_priv = NM_DEVICE_GET_PRIVATE (slave); - if (!configure) { - g_warn_if_fail (reason == NM_DEVICE_STATE_REASON_NONE || reason == NM_DEVICE_STATE_REASON_REMOVED); - reason = NM_DEVICE_STATE_REASON_NONE; - } else if (reason == NM_DEVICE_STATE_REASON_NONE) { - g_warn_if_reached (); - reason = NM_DEVICE_STATE_REASON_UNKNOWN; - } - nm_device_slave_notify_release (info->slave, reason); + g_return_if_fail (self == slave_priv->master); + nm_assert (slave == info->slave); + + /* first, let subclasses handle the release ... */ + if (info->slave_is_enslaved) + NM_DEVICE_GET_CLASS (self)->release_slave (self, slave, configure); + + /* raise notifications about the release, including clearing is_enslaved. */ + nm_device_slave_notify_release (slave, reason); + + /* keep both alive until the end of the function. + * Transfers ownership from slave_priv->master. */ + self_free = self; - free_slave_info (info); + priv->slaves = g_slist_remove (priv->slaves, info); + slave_priv->master = NULL; + + g_signal_handler_disconnect (slave, info->watch_id); + g_object_unref (slave); + g_slice_free (SlaveInfo, info); /* Ensure the device's hardware address is up-to-date; it often changes * when slaves change. */ nm_device_update_hw_address (self); - - return success; } /** @@ -1123,8 +1170,7 @@ nm_device_release_one_slave (NMDevice *self, NMDevice *slave, gboolean configure static gboolean can_unmanaged_external_down (NMDevice *self) { - return nm_device_is_software (self) - && !nm_device_get_is_nm_owned (self); + return nm_device_is_software (self) && !NM_DEVICE_GET_PRIVATE (self)->is_nm_owned; } /** @@ -1138,7 +1184,6 @@ void nm_device_finish_init (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean platform_unmanaged = FALSE; g_assert (priv->initialized == FALSE); @@ -1147,29 +1192,29 @@ nm_device_finish_init (NMDevice *self) && priv->ifindex > 0 && ( !priv->up || !priv->platform_link_initialized)) - nm_device_set_initial_unmanaged_flag (self, NM_UNMANAGED_EXTERNAL_DOWN, TRUE); + nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_EXTERNAL_DOWN, TRUE); if (priv->master) - nm_device_enslave_slave (priv->master, self, NULL); + nm_device_master_enslave_slave (priv->master, self, NULL); if (priv->ifindex > 0) { if (priv->ifindex == 1) { - /* keep 'lo' as default-unmanaged. */ - - /* FIXME: either find a better way to unmange 'lo' that cannot be changed - * by user configuration (NM_UNMANGED_LOOPBACK?) or fix managing 'lo'. - * Currently it can happen that NM deletes 127.0.0.1 address. */ - nm_device_set_initial_unmanaged_flag (self, NM_UNMANAGED_DEFAULT, TRUE); + /* Unmanaged the loopback device with an explicit NM_UNMANAGED_LOOPBACK flag. + * Later we might want to manage 'lo' too. Currently that doesn't work because + * NetworkManager might down the interface or remove the 127.0.0.1 address. */ + nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_LOOPBACK, TRUE); } else if (priv->platform_link_initialized || (priv->is_nm_owned && nm_device_is_software (self))) { + gboolean platform_unmanaged = FALSE; + if (nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged)) - nm_device_set_initial_unmanaged_flag (self, NM_UNMANAGED_DEFAULT, platform_unmanaged); + nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_DEFAULT, platform_unmanaged); } else { /* Hardware and externally-created software links stay unmanaged * until they are fully initialized by the platform. NM created * links must be available for activation immediately and thus * do not get the PLATFORM_INIT unmanaged flag set. */ - nm_device_set_initial_unmanaged_flag (self, NM_UNMANAGED_PLATFORM_INIT, TRUE); + nm_device_set_unmanaged_flags_initial (self, NM_UNMANAGED_PLATFORM_INIT, TRUE); } } @@ -1180,6 +1225,9 @@ static void update_dynamic_ip_setup (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + GError *error; + gconstpointer addr; + size_t addr_length; g_hash_table_remove_all (priv->ip6_saved_properties); @@ -1205,6 +1253,18 @@ update_dynamic_ip_setup (NMDevice *self) if (priv->dnsmasq_manager) { /* FIXME: todo */ } + + if (priv->lldp_listener && nm_lldp_listener_is_running (priv->lldp_listener)) { + nm_lldp_listener_stop (priv->lldp_listener); + addr = nm_platform_link_get_address (NM_PLATFORM_GET, priv->ifindex, &addr_length); + + if (!nm_lldp_listener_start (priv->lldp_listener, nm_device_get_ifindex (self), + nm_device_get_iface (self), addr, addr_length, &error)) { + _LOGD (LOGD_DEVICE, "LLDP listener %p could not be restarted: %s", + priv->lldp_listener, error->message); + g_clear_error (&error); + } + } } static void @@ -1342,23 +1402,40 @@ nm_device_set_carrier (NMDevice *self, gboolean carrier) } static void -device_set_master (NMDevice *self, int ifindex) +device_recheck_slave_status (NMDevice *self, const NMPlatformLink *plink) { - NMDevice *master; NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - master = nm_manager_get_device_by_ifindex (nm_manager_get (), ifindex); - if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) { - g_clear_object (&priv->master); - priv->master = g_object_ref (master); - nm_device_master_add_slave (master, self, FALSE); - } else if (master) { - _LOGI (LOGD_DEVICE, "enslaved to non-master-type device %s; ignoring", - nm_device_get_iface (master)); - } else { - _LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s", - ifindex, - nm_platform_link_get_name (NM_PLATFORM_GET, ifindex)); + g_return_if_fail (plink); + + if (plink->master <= 0) + return; + + if (priv->master) { + if ( plink->master > 0 + && plink->master == nm_device_get_ifindex (priv->master)) { + /* call add-slave again. We expect @self already to be added to + * the master, but this also triggers a recheck-assume. */ + nm_device_master_add_slave (priv->master, self, FALSE); + return; + } + + nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + } + if (plink->master > 0) { + NMDevice *master; + + master = nm_manager_get_device_by_ifindex (nm_manager_get (), plink->master); + if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) + nm_device_master_add_slave (master, self, FALSE); + else if (master) { + _LOGI (LOGD_DEVICE, "enslaved to non-master-type device %s; ignoring", + nm_device_get_iface (master)); + } else { + _LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s", + plink->master, + nm_platform_link_get_name (NM_PLATFORM_GET, plink->master)); + } } } @@ -1369,12 +1446,11 @@ device_link_changed (NMDevice *self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMUtilsIPv6IfaceId token_iid; gboolean ip_ifname_changed = FALSE; - gboolean platform_unmanaged = FALSE; const char *udi; NMPlatformLink info; const NMPlatformLink *pllink; int ifindex; - gboolean emit_link_initialized = FALSE; + gboolean just_initialized = FALSE; gboolean was_up; priv->device_link_changed_id = 0; @@ -1407,6 +1483,12 @@ device_link_changed (NMDevice *self) g_object_notify (G_OBJECT (self), NM_DEVICE_MTU); } + if (info.driver && g_strcmp0 (priv->driver, info.driver) != 0) { + g_free (priv->driver); + priv->driver = g_strdup (info.driver); + g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER); + } + if (info.name[0] && strcmp (priv->iface, info.name) != 0) { _LOGI (LOGD_DEVICE, "interface index %d renamed iface from '%s' to '%s'", priv->ifindex, priv->iface, info.name); @@ -1429,15 +1511,6 @@ device_link_changed (NMDevice *self) nm_device_emit_recheck_auto_activate (self); } - /* Update slave status for external changes */ - if (priv->enslaved && info.master != nm_device_get_ifindex (priv->master)) - nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_NONE); - if (info.master && !priv->enslaved) { - device_set_master (self, info.master); - if (priv->master) - nm_device_enslave_slave (priv->master, self, NULL); - } - if (priv->rdisc && nm_platform_link_get_ipv6_token (NM_PLATFORM_GET, priv->ifindex, &token_iid)) { _LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface); if (nm_rdisc_set_iid (priv->rdisc, token_iid)) @@ -1452,33 +1525,36 @@ device_link_changed (NMDevice *self) update_dynamic_ip_setup (self); if (priv->ifindex > 0 && !priv->platform_link_initialized && info.initialized) { + gboolean platform_unmanaged = FALSE; + priv->platform_link_initialized = TRUE; if (nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged)) { - nm_device_set_unmanaged (self, - NM_UNMANAGED_DEFAULT, - platform_unmanaged, - NM_DEVICE_STATE_REASON_USER_REQUESTED); + nm_device_set_unmanaged_flags (self, + NM_UNMANAGED_DEFAULT, + platform_unmanaged, + NM_DEVICE_STATE_REASON_USER_REQUESTED); } - nm_device_set_unmanaged (self, - NM_UNMANAGED_PLATFORM_INIT, - FALSE, - NM_DEVICE_STATE_REASON_NOW_MANAGED); + nm_device_set_unmanaged_flags (self, + NM_UNMANAGED_PLATFORM_INIT, + FALSE, + NM_DEVICE_STATE_REASON_NOW_MANAGED); - emit_link_initialized = TRUE; + just_initialized = TRUE; } was_up = priv->up; priv->up = NM_FLAGS_HAS (info.flags, IFF_UP); if ( priv->platform_link_initialized - && (emit_link_initialized || priv->up != was_up)) { + && ( just_initialized + || priv->up != was_up)) { /* Manage externally-created software interfaces only when they are IFF_UP */ g_assert (priv->ifindex > 0); if (NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)) { - gboolean external_down = nm_device_get_unmanaged_flag (self, NM_UNMANAGED_EXTERNAL_DOWN); + gboolean external_down = !!nm_device_get_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN); if (external_down && NM_FLAGS_HAS (info.flags, IFF_UP)) { if (nm_device_get_state (self) < NM_DEVICE_STATE_DISCONNECTED) { @@ -1492,32 +1568,30 @@ device_link_changed (NMDevice *self) * the device before assumption occurs, pass * NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED as the reason. */ - nm_device_set_unmanaged (self, - NM_UNMANAGED_EXTERNAL_DOWN, - FALSE, - NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + nm_device_set_unmanaged_flags (self, + NM_UNMANAGED_EXTERNAL_DOWN, + FALSE, + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); } else { /* Don't trigger a state change; if the device is in a * state higher than UNAVAILABLE, it is already IFF_UP * or an explicit activation request was received. */ - priv->unmanaged_flags &= ~NM_UNMANAGED_EXTERNAL_DOWN; + _set_unmanaged_flags (self, NM_UNMANAGED_EXTERNAL_DOWN, FALSE); } } else if (!external_down && !NM_FLAGS_HAS (info.flags, IFF_UP) && nm_device_get_state (self) <= NM_DEVICE_STATE_DISCONNECTED) { /* If the device is already disconnected and is set !IFF_UP, * unmanage it. */ - nm_device_set_unmanaged (self, - NM_UNMANAGED_EXTERNAL_DOWN, - TRUE, - NM_DEVICE_STATE_REASON_USER_REQUESTED); + nm_device_set_unmanaged_flags (self, + NM_UNMANAGED_EXTERNAL_DOWN, + TRUE, + NM_DEVICE_STATE_REASON_USER_REQUESTED); } } } - if (emit_link_initialized) - g_signal_emit (self, signals[LINK_INITIALIZED], 0); - + device_recheck_slave_status (self, &info); return G_SOURCE_REMOVE; } @@ -1526,12 +1600,13 @@ device_ip_link_changed (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); const NMPlatformLink *pllink; - int ip_ifindex; priv->device_ip_link_changed_id = 0; - ip_ifindex = nm_device_get_ip_ifindex (self); - pllink = nm_platform_link_get (NM_PLATFORM_GET, ip_ifindex); + if (!priv->ip_ifindex) + return G_SOURCE_REMOVE; + + pllink = nm_platform_link_get (NM_PLATFORM_GET, priv->ip_ifindex); if (!pllink) return G_SOURCE_REMOVE; @@ -1554,7 +1629,6 @@ link_changed_cb (NMPlatform *platform, int ifindex, NMPlatformLink *info, NMPlatformSignalChangeType change_type, - NMPlatformReason reason, NMDevice *self) { NMDevicePrivate *priv; @@ -1564,12 +1638,6 @@ link_changed_cb (NMPlatform *platform, priv = NM_DEVICE_GET_PRIVATE (self); - /* We don't filter by 'reason' because we are interested in *all* link - * changes. For example a call to nm_platform_link_set_up() may result - * in an internal carrier change (i.e. we ask the kernel to set IFF_UP - * and it results in also setting IFF_LOWER_UP. - */ - if (ifindex == nm_device_get_ifindex (self)) { if (!priv->device_link_changed_id) { priv->device_link_changed_id = g_idle_add ((GSourceFunc) device_link_changed, self); @@ -1592,154 +1660,650 @@ link_changed (NMDevice *self, NMPlatformLink *info) nm_device_set_carrier (self, info->connected); } -static void -config_changed_update_ignore_carrier (NMConfig *config, - NMConfigData *config_data, - NMConfigChangeFlags changes, - NMConfigData *old_data, - NMDevice *self) +static gboolean +link_type_compatible (NMDevice *self, + NMLinkType link_type, + gboolean *out_compatible, + GError **error) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDeviceClass *klass; + NMLinkType device_type; + guint i = 0; - if ( priv->state <= NM_DEVICE_STATE_DISCONNECTED - || priv->state > NM_DEVICE_STATE_ACTIVATED) - priv->ignore_carrier = nm_config_data_get_ignore_carrier (config_data, self); -} + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); -static void -check_carrier (NMDevice *self) -{ - int ifindex = nm_device_get_ip_ifindex (self); + klass = NM_DEVICE_GET_CLASS (self); - if (!nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) - nm_device_set_carrier (self, nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex)); + if (!klass->link_types) { + NM_SET_OUT (out_compatible, FALSE); + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "Device does not support platform links"); + return FALSE; + } + + device_type = self->priv->link_type; + if (device_type > NM_LINK_TYPE_UNKNOWN && device_type != link_type) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "Needed link type 0x%x does not match the platform link type 0x%X", + device_type, link_type); + return FALSE; + } + + for (i = 0; klass->link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) { + if (klass->link_types[i] == link_type) + return TRUE; + if (klass->link_types[i] == NM_LINK_TYPE_ANY) + return TRUE; + } + + NM_SET_OUT (out_compatible, FALSE); + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "Device does not support platform link type 0x%X", + link_type); + return FALSE; } /** - * nm_device_notify_component_added(): + * nm_device_realize_start(): * @self: the #NMDevice - * @component: the component being added by a plugin + * @plink: an existing platform link or %NULL + * @out_compatible: %TRUE on return if @self is compatible with @plink + * @error: location to store error, or %NULL * - * Called by the manager to notify the device that a new component has - * been found. The device implementation should return %TRUE if it - * wishes to claim the component, or %FALSE if it cannot. + * Initializes and sets up the device using existing backing resources. Before + * the device is ready for use nm_device_realize_finish() must be called. + * @out_compatible will only be set if @plink is not %NULL, and * - * Returns: %TRUE to claim the component, %FALSE if the component cannot be - * claimed. + * Important: if nm_device_realize_start() returns %TRUE, the caller MUST + * also call nm_device_realize_finish() to balance g_object_freeze_notify(). + * + * Returns: %TRUE on success, %FALSE on error */ gboolean -nm_device_notify_component_added (NMDevice *self, GObject *component) -{ - if (NM_DEVICE_GET_CLASS (self)->component_added) - return NM_DEVICE_GET_CLASS (self)->component_added (self, component); - return FALSE; +nm_device_realize_start (NMDevice *self, + const NMPlatformLink *plink, + gboolean *out_compatible, + GError **error) +{ + NM_SET_OUT (out_compatible, TRUE); + + if (plink) { + if (g_strcmp0 (nm_device_get_iface (self), plink->name) != 0) { + NM_SET_OUT (out_compatible, FALSE); + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "Device interface name does not match platform link"); + return FALSE; + } + + if (!link_type_compatible (self, plink->type, out_compatible, error)) + return FALSE; + } + + realize_start_setup (self, plink); + + return TRUE; } /** - * nm_device_owns_iface(): + * nm_device_create_and_realize(): * @self: the #NMDevice - * @iface: an interface name + * @connection: the #NMConnection being activated + * @parent: the parent #NMDevice if any + * @error: location to store error, or %NULL * - * Called by the manager to ask if the device or any of its components owns - * @iface. For example, a WWAN implementation would return %TRUE for an - * ethernet interface name that was owned by the WWAN device's modem component, - * because that ethernet interface is controlled by the WWAN device and cannot - * be used independently of the WWAN device. + * Creates any backing resources needed to realize the device to proceed + * with activating @connection. * - * Returns: %TRUE if @self or it's components owns the interface name, - * %FALSE if not + * Returns: %TRUE on success, %FALSE on error */ gboolean -nm_device_owns_iface (NMDevice *self, const char *iface) +nm_device_create_and_realize (NMDevice *self, + NMConnection *connection, + NMDevice *parent, + GError **error) { - if (NM_DEVICE_GET_CLASS (self)->owns_iface) - return NM_DEVICE_GET_CLASS (self)->owns_iface (self, iface); - return FALSE; -} + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMPlatformLink plink_copy; + const NMPlatformLink *plink = NULL; -NMConnection * -nm_device_new_default_connection (NMDevice *self) -{ - if (NM_DEVICE_GET_CLASS (self)->new_default_connection) - return NM_DEVICE_GET_CLASS (self)->new_default_connection (self); - return NULL; + /* Must be set before device is realized */ + priv->is_nm_owned = !nm_platform_link_get_by_ifname (NM_PLATFORM_GET, priv->iface); + + _LOGD (LOGD_DEVICE, "create (is %snm-owned)", priv->is_nm_owned ? "" : "not "); + + /* Create any resources the device needs */ + if (NM_DEVICE_GET_CLASS (self)->create_and_realize) { + if (!NM_DEVICE_GET_CLASS (self)->create_and_realize (self, connection, parent, &plink, error)) + return FALSE; + plink_copy = *plink; + plink = &plink_copy; + } + + realize_start_setup (self, plink); + nm_device_realize_finish (self, plink); + + g_return_val_if_fail (nm_device_check_connection_compatible (self, connection), TRUE); + return TRUE; } static void -slave_state_changed (NMDevice *slave, - NMDeviceState slave_new_state, - NMDeviceState slave_old_state, - NMDeviceStateReason reason, - NMDevice *self) +update_device_from_platform_link (NMDevice *self, const NMPlatformLink *plink) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - gboolean release = FALSE; + const char *udi; - _LOGD (LOGD_DEVICE, "slave %s state change %d (%s) -> %d (%s)", - nm_device_get_iface (slave), - slave_old_state, - state_to_string (slave_old_state), - slave_new_state, - state_to_string (slave_new_state)); + g_return_if_fail (plink != NULL); - /* Don't try to enslave slaves until the master is ready */ - if (priv->state < NM_DEVICE_STATE_CONFIG) - return; + udi = nm_platform_link_get_udi (NM_PLATFORM_GET, plink->ifindex); + if (udi && !g_strcmp0 (udi, priv->udi)) { + g_free (priv->udi); + priv->udi = g_strdup (udi); + g_object_notify (G_OBJECT (self), NM_DEVICE_UDI); + } - if (slave_new_state == NM_DEVICE_STATE_IP_CONFIG) - nm_device_enslave_slave (self, slave, nm_device_get_connection (slave)); - else if (slave_new_state > NM_DEVICE_STATE_ACTIVATED) - release = TRUE; - else if ( slave_new_state <= NM_DEVICE_STATE_DISCONNECTED - && slave_old_state > NM_DEVICE_STATE_DISCONNECTED) { - /* Catch failures due to unavailable or unmanaged */ - release = TRUE; + if (!g_strcmp0 (plink->name, priv->iface)) { + g_free (priv->iface); + priv->iface = g_strdup (plink->name); + g_object_notify (G_OBJECT (self), NM_DEVICE_IFACE); } - if (release) { - nm_device_release_one_slave (self, slave, TRUE, reason); - /* Bridge/bond/team interfaces are left up until manually deactivated */ - if (priv->slaves == NULL && priv->state == NM_DEVICE_STATE_ACTIVATED) - _LOGD (LOGD_DEVICE, "last slave removed; remaining activated"); + priv->ifindex = plink->ifindex; + g_object_notify (G_OBJECT (self), NM_DEVICE_IFINDEX); + + priv->up = NM_FLAGS_HAS (plink->flags, IFF_UP); + if (plink->driver && g_strcmp0 (plink->driver, priv->driver) != 0) { + g_free (priv->driver); + priv->driver = g_strdup (plink->driver); + g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER); } + priv->platform_link_initialized = plink->initialized; } -/** - * nm_device_master_add_slave: - * @self: the master device - * @slave: the slave device to enslave - * @configure: pass %TRUE if the slave should be configured by the master, or - * %FALSE if it is already configured outside NetworkManager - * - * If @self is capable of enslaving other devices (ie it's a bridge, bond, team, - * etc) then this function adds @slave to the slave list for later enslavement. - * - * Returns: %TRUE on success, %FALSE on failure +static void +config_changed_update_ignore_carrier (NMConfig *config, + NMConfigData *config_data, + NMConfigChangeFlags changes, + NMConfigData *old_data, + NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if ( priv->state <= NM_DEVICE_STATE_DISCONNECTED + || priv->state > NM_DEVICE_STATE_ACTIVATED) + priv->ignore_carrier = nm_config_data_get_ignore_carrier (config_data, self); +} + +static void +check_carrier (NMDevice *self) +{ + int ifindex = nm_device_get_ip_ifindex (self); + + if (!nm_device_has_capability (self, NM_DEVICE_CAP_NONSTANDARD_CARRIER)) + nm_device_set_carrier (self, nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex)); +} + +static void +realize_start_notify (NMDevice *self, const NMPlatformLink *plink) +{ + /* Stub implementation for realize_start_notify(). It does nothing, + * but allows derived classes to uniformly invoke the parent + * implementation. */ +} + +/** + * realize_start_setup(): + * @self: the #NMDevice + * @plink: the #NMPlatformLink if backed by a kernel netdevice + * + * Update the device from backing resource properties (like hardware + * addresses, carrier states, driver/firmware info, etc). This function + * should only change properties for this device, and should not perform + * any tasks that affect other interfaces (like master/slave or parent/child + * stuff). */ +static void +realize_start_setup (NMDevice *self, const NMPlatformLink *plink) +{ + NMDevicePrivate *priv; + NMDeviceClass *klass; + static guint32 id = 0; + + g_return_if_fail (NM_IS_DEVICE (self)); + + priv = NM_DEVICE_GET_PRIVATE (self); + + /* The device should not be realized */ + g_return_if_fail (!priv->real); + g_return_if_fail (priv->ip_ifindex <= 0); + g_return_if_fail (priv->ip_iface == NULL); + + _LOGD (LOGD_DEVICE, "start setup of %s, kernel ifindex %d", G_OBJECT_TYPE_NAME (self), plink ? plink->ifindex : 0); + + klass = NM_DEVICE_GET_CLASS (self); + + /* Balanced by a thaw in nm_device_realize_finish() */ + g_object_freeze_notify (G_OBJECT (self)); + + if (plink) { + g_return_if_fail (link_type_compatible (self, plink->type, NULL, NULL)); + update_device_from_platform_link (self, plink); + } + + if (priv->ifindex > 0) { + priv->physical_port_id = nm_platform_link_get_physical_port_id (NM_PLATFORM_GET, priv->ifindex); + g_object_notify (G_OBJECT (self), NM_DEVICE_PHYSICAL_PORT_ID); + + priv->dev_id = nm_platform_link_get_dev_id (NM_PLATFORM_GET, priv->ifindex); + + if (nm_platform_link_is_software (NM_PLATFORM_GET, priv->ifindex)) + priv->capabilities |= NM_DEVICE_CAP_IS_SOFTWARE; + + priv->mtu = nm_platform_link_get_mtu (NM_PLATFORM_GET, priv->ifindex); + g_object_notify (G_OBJECT (self), NM_DEVICE_MTU); + + nm_platform_link_get_driver_info (NM_PLATFORM_GET, + priv->ifindex, + NULL, + &priv->driver_version, + &priv->firmware_version); + if (priv->driver_version) + g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER_VERSION); + if (priv->firmware_version) + g_object_notify (G_OBJECT (self), NM_DEVICE_FIRMWARE_VERSION); + + if (nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET)) + priv->nm_ipv6ll = nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, priv->ifindex); + } + + if (klass->get_generic_capabilities) + priv->capabilities |= klass->get_generic_capabilities (self); + + if (!priv->udi) { + /* Use a placeholder UDI until we get a real one */ + priv->udi = g_strdup_printf ("/virtual/device/placeholder/%d", id++); + g_object_notify (G_OBJECT (self), NM_DEVICE_UDI); + } + + /* trigger initial ip config change to initialize ip-config */ + priv->queued_ip4_config_id = g_idle_add (queued_ip4_config_change, self); + priv->queued_ip6_config_id = g_idle_add (queued_ip6_config_change, self); + + nm_device_update_hw_address (self); + nm_device_update_initial_hw_address (self); + + /* Note: initial hardware address must be read before calling get_ignore_carrier() */ + if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { + NMConfig *config = nm_config_get (); + + priv->ignore_carrier = nm_config_data_get_ignore_carrier (nm_config_get_data (config), self); + g_signal_connect (G_OBJECT (config), + NM_CONFIG_SIGNAL_CONFIG_CHANGED, + G_CALLBACK (config_changed_update_ignore_carrier), + self); + + check_carrier (self); + _LOGD (LOGD_HW, + "carrier is %s%s", + priv->carrier ? "ON" : "OFF", + priv->ignore_carrier ? " (but ignored)" : ""); + } else { + /* Fake online link when carrier detection is not available. */ + priv->carrier = TRUE; + } + + g_object_notify (G_OBJECT (self), NM_DEVICE_CAPABILITIES); + + klass->realize_start_notify (self, plink); +} + +/** + * nm_device_realize_finish(): + * @self: the #NMDevice + * @plink: the #NMPlatformLink if backed by a kernel netdevice + * + * Update the device's master/slave or parent/child relationships from + * backing resource properties. After this function finishes, the device + * is ready for network connectivity. + */ +void +nm_device_realize_finish (NMDevice *self, const NMPlatformLink *plink) +{ + NMDevicePrivate *priv; + + g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail (!plink || link_type_compatible (self, plink->type, NULL, NULL)); + + priv = NM_DEVICE_GET_PRIVATE (self); + + g_return_if_fail (!priv->real); + + if (plink) { + update_device_from_platform_link (self, plink); + device_recheck_slave_status (self, plink); + } + + priv->real = TRUE; + g_object_notify (G_OBJECT (self), NM_DEVICE_REAL); + + nm_device_recheck_available_connections (self); + + /* Balanced by a freeze in realize_start_setup() */ + g_object_thaw_notify (G_OBJECT (self)); +} + +static void +unrealize_notify (NMDevice *self) +{ + /* Stub implementation for unrealize_notify(). It does nothing, + * but allows derived classes to uniformly invoke the parent + * implementation. */ +} + static gboolean -nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure) +available_connection_check_delete_unrealized_on_idle (gpointer user_data) +{ + NMDevice *self = user_data; + NMDevicePrivate *priv; + + g_return_val_if_fail (NM_IS_DEVICE (self), G_SOURCE_REMOVE); + + priv = NM_DEVICE_GET_PRIVATE (self); + + priv->check_delete_unrealized_id = 0; + + if ( g_hash_table_size (priv->available_connections) == 0 + && !nm_device_is_real (self)) + g_signal_emit (self, signals[REMOVED], 0); + + return G_SOURCE_REMOVE; +} + +static void +available_connection_check_delete_unrealized (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + /* always rescheadule the remove signal. */ + nm_clear_g_source (&priv->check_delete_unrealized_id); + + if ( g_hash_table_size (priv->available_connections) == 0 + && !nm_device_is_real (self)) + priv->check_delete_unrealized_id = g_idle_add (available_connection_check_delete_unrealized_on_idle, self); +} + +/** + * nm_device_unrealize(): + * @self: the #NMDevice + * @remove_resources: if %TRUE, remove backing resources + * @error: location to store error, or %NULL + * + * Clears any properties that depend on backing resources (kernel devices, + * etc) and removes those resources if @remove_resources is %TRUE. + * + * Returns: %TRUE on success, %FALSE on error + */ +gboolean +nm_device_unrealize (NMDevice *self, gboolean remove_resources, GError **error) +{ + NMDevicePrivate *priv; + int ifindex; + + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + + if (!nm_device_is_software (self) || !nm_device_is_real (self)) { + g_set_error_literal (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_SOFTWARE, + "This device is not a software device or is not realized"); + return FALSE; + } + + priv = NM_DEVICE_GET_PRIVATE (self); + + g_return_val_if_fail (priv->iface != NULL, FALSE); + g_return_val_if_fail (priv->real, FALSE); + + g_object_freeze_notify (G_OBJECT (self)); + + ifindex = nm_device_get_ifindex (self); + + _LOGD (LOGD_DEVICE, "unrealize (ifindex %d)", ifindex > 0 ? ifindex : 0); + + if (remove_resources) { + if (ifindex > 0) + nm_platform_link_delete (NM_PLATFORM_GET, ifindex); + } + + NM_DEVICE_GET_CLASS (self)->unrealize_notify (self); + + if (priv->ifindex > 0) { + priv->ifindex = 0; + g_object_notify (G_OBJECT (self), NM_DEVICE_IFINDEX); + } + priv->ip_ifindex = 0; + if (priv->ip_iface) { + g_clear_pointer (&priv->ip_iface, g_free); + g_object_notify (G_OBJECT (self), NM_DEVICE_IP_IFACE); + } + if (priv->driver_version) { + g_clear_pointer (&priv->driver_version, g_free); + g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER_VERSION); + } + if (priv->firmware_version) { + g_clear_pointer (&priv->firmware_version, g_free); + g_object_notify (G_OBJECT (self), NM_DEVICE_FIRMWARE_VERSION); + } + if (priv->udi) { + g_clear_pointer (&priv->udi, g_free); + g_object_notify (G_OBJECT (self), NM_DEVICE_UDI); + } + if (priv->hw_addr) { + g_clear_pointer (&priv->hw_addr, g_free); + g_object_notify (G_OBJECT (self), NM_DEVICE_HW_ADDRESS); + } + if (priv->physical_port_id) { + g_clear_pointer (&priv->physical_port_id, g_free); + g_object_notify (G_OBJECT (self), NM_DEVICE_PHYSICAL_PORT_ID); + } + + g_clear_pointer (&priv->perm_hw_addr, g_free); + g_clear_pointer (&priv->initial_hw_addr, g_free); + + priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED; + if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities) + priv->capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self); + g_object_notify (G_OBJECT (self), NM_DEVICE_CAPABILITIES); + + priv->real = FALSE; + g_object_notify (G_OBJECT (self), NM_DEVICE_REAL); + + nm_device_set_autoconnect (self, DEFAULT_AUTOCONNECT); + + g_object_thaw_notify (G_OBJECT (self)); + + nm_device_state_changed (self, + NM_DEVICE_STATE_UNMANAGED, + remove_resources ? + NM_DEVICE_STATE_REASON_USER_REQUESTED : NM_DEVICE_STATE_REASON_NOW_UNMANAGED); + + /* Garbage-collect unneeded unrealized devices. */ + nm_device_recheck_available_connections (self); + + return TRUE; +} + +/** + * nm_device_notify_new_device_added(): + * @self: the #NMDevice + * @device: the newly added device + * + * Called by the manager to notify the device that a new device has + * been found and added. + */ +void +nm_device_notify_new_device_added (NMDevice *self, NMDevice *device) +{ + NMDeviceClass *klass; + + g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail (NM_IS_DEVICE (device)); + + klass = NM_DEVICE_GET_CLASS (self); + if (klass->notify_new_device_added) + klass->notify_new_device_added (self, device); +} + +/** + * nm_device_notify_component_added(): + * @self: the #NMDevice + * @component: the component being added by a plugin + * + * Called by the manager to notify the device that a new component has + * been found. The device implementation should return %TRUE if it + * wishes to claim the component, or %FALSE if it cannot. + * + * Returns: %TRUE to claim the component, %FALSE if the component cannot be + * claimed. + */ +gboolean +nm_device_notify_component_added (NMDevice *self, GObject *component) +{ + NMDeviceClass *klass; + + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail (G_IS_OBJECT (component), FALSE); + + klass = NM_DEVICE_GET_CLASS (self); + if (klass->component_added) + return klass->component_added (self, component); + return FALSE; +} + +/** + * nm_device_owns_iface(): + * @self: the #NMDevice + * @iface: an interface name + * + * Called by the manager to ask if the device or any of its components owns + * @iface. For example, a WWAN implementation would return %TRUE for an + * ethernet interface name that was owned by the WWAN device's modem component, + * because that ethernet interface is controlled by the WWAN device and cannot + * be used independently of the WWAN device. + * + * Returns: %TRUE if @self or it's components owns the interface name, + * %FALSE if not + */ +gboolean +nm_device_owns_iface (NMDevice *self, const char *iface) +{ + if (NM_DEVICE_GET_CLASS (self)->owns_iface) + return NM_DEVICE_GET_CLASS (self)->owns_iface (self, iface); + return FALSE; +} + +NMConnection * +nm_device_new_default_connection (NMDevice *self) +{ + if (NM_DEVICE_GET_CLASS (self)->new_default_connection) + return NM_DEVICE_GET_CLASS (self)->new_default_connection (self); + return NULL; +} + +static void +slave_state_changed (NMDevice *slave, + NMDeviceState slave_new_state, + NMDeviceState slave_old_state, + NMDeviceStateReason reason, + NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gboolean release = FALSE; + + _LOGD (LOGD_DEVICE, "slave %s state change %d (%s) -> %d (%s)", + nm_device_get_iface (slave), + slave_old_state, + state_to_string (slave_old_state), + slave_new_state, + state_to_string (slave_new_state)); + + /* Don't try to enslave slaves until the master is ready */ + if (priv->state < NM_DEVICE_STATE_CONFIG) + return; + + if (slave_new_state == NM_DEVICE_STATE_IP_CONFIG) + nm_device_master_enslave_slave (self, slave, nm_device_get_applied_connection (slave)); + else if (slave_new_state > NM_DEVICE_STATE_ACTIVATED) + release = TRUE; + else if ( slave_new_state <= NM_DEVICE_STATE_DISCONNECTED + && slave_old_state > NM_DEVICE_STATE_DISCONNECTED) { + /* Catch failures due to unavailable or unmanaged */ + release = TRUE; + } + + if (release) { + nm_device_master_release_one_slave (self, slave, TRUE, reason); + /* Bridge/bond/team interfaces are left up until manually deactivated */ + if (priv->slaves == NULL && priv->state == NM_DEVICE_STATE_ACTIVATED) + _LOGD (LOGD_DEVICE, "last slave removed; remaining activated"); + } +} + +/** + * nm_device_master_add_slave: + * @self: the master device + * @slave: the slave device to enslave + * @configure: pass %TRUE if the slave should be configured by the master, or + * %FALSE if it is already configured outside NetworkManager + * + * If @self is capable of enslaving other devices (ie it's a bridge, bond, team, + * etc) then this function adds @slave to the slave list for later enslavement. + */ +static void +nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure) +{ + NMDevicePrivate *priv; + NMDevicePrivate *slave_priv; SlaveInfo *info; - g_return_val_if_fail (self != NULL, FALSE); - g_return_val_if_fail (slave != NULL, FALSE); - g_return_val_if_fail (NM_DEVICE_GET_CLASS (self)->enslave_slave != NULL, FALSE); + g_return_if_fail (NM_IS_DEVICE (self)); + g_return_if_fail (NM_IS_DEVICE (slave)); + g_return_if_fail (NM_DEVICE_GET_CLASS (self)->enslave_slave != NULL); + + priv = NM_DEVICE_GET_PRIVATE (self); + slave_priv = NM_DEVICE_GET_PRIVATE (slave); + + info = find_slave_info (self, slave); + + _LOGt (LOGD_CORE, "master: add one slave %p/%s%s", slave, nm_device_get_iface (slave), + info ? " (already registered)" : ""); if (configure) - g_return_val_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); + g_return_if_fail (nm_device_get_state (slave) >= NM_DEVICE_STATE_DISCONNECTED); - if (!find_slave_info (self, slave)) { - info = g_malloc0 (sizeof (SlaveInfo)); + if (!info) { + g_return_if_fail (!slave_priv->master); + g_return_if_fail (!slave_priv->is_enslaved); + + info = g_slice_new0 (SlaveInfo); info->slave = g_object_ref (slave); info->configure = configure; - info->watch_id = g_signal_connect (slave, "state-changed", + info->watch_id = g_signal_connect (slave, + NM_DEVICE_STATE_CHANGED, G_CALLBACK (slave_state_changed), self); priv->slaves = g_slist_append (priv->slaves, info); - } - nm_device_queue_recheck_assume (self); + slave_priv->master = g_object_ref (self); - return TRUE; + /* no need to emit + * + * g_object_notify (G_OBJECT (slave), NM_DEVICE_MASTER); + * + * because slave_priv->is_enslaved is not true, thus the value + * didn't change yet. */ + } else + g_return_if_fail (slave_priv->master == self); + + nm_device_queue_recheck_assume (self); + nm_device_queue_recheck_assume (slave); } @@ -1749,7 +2313,7 @@ nm_device_master_add_slave (NMDevice *self, NMDevice *slave, gboolean configure) * * Returns: any slaves of which @self is the master. Caller owns returned list. */ -GSList * +static GSList * nm_device_master_get_slaves (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -1794,7 +2358,7 @@ nm_device_master_get_slave_by_ifindex (NMDevice *self, int ifindex) */ void nm_device_master_check_slave_physical_port (NMDevice *self, NMDevice *slave, - guint64 log_domain) + NMLogDomain log_domain) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); const char *slave_physical_port_id, *existing_physical_port_id; @@ -1831,6 +2395,7 @@ nm_device_master_release_slaves (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDeviceStateReason reason; + gboolean configure = TRUE; /* Don't release the slaves if this connection doesn't belong to NM. */ if (nm_device_uses_generated_assumed_connection (self)) @@ -1840,13 +2405,28 @@ nm_device_master_release_slaves (NMDevice *self) if (priv->state == NM_DEVICE_STATE_FAILED) reason = NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED; + if (!nm_platform_link_get (NM_PLATFORM_GET, priv->ifindex)) + configure = FALSE; + while (priv->slaves) { SlaveInfo *info = priv->slaves->data; - nm_device_release_one_slave (self, info->slave, TRUE, reason); + nm_device_master_release_one_slave (self, info->slave, configure, reason); } } +/** + * nm_device_is_master: + * @self: the device + * + * Returns: %TRUE if the device can have slaves + */ +gboolean +nm_device_is_master (NMDevice *self) +{ + return NM_DEVICE_GET_PRIVATE (self)->is_master; +} + /** * nm_device_get_master: * @self: the device @@ -1863,10 +2443,11 @@ nm_device_get_master (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->enslaved) + if (priv->is_enslaved) { + g_return_val_if_fail (priv->master, NULL); return priv->master; - else - return NULL; + } + return NULL; } /** @@ -1881,12 +2462,12 @@ static void nm_device_slave_notify_enslave (NMDevice *self, gboolean success) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection = nm_device_get_connection (self); + NMConnection *connection = nm_device_get_applied_connection (self); gboolean activating = (priv->state == NM_DEVICE_STATE_IP_CONFIG); - g_assert (priv->master); + g_return_if_fail (priv->master); - if (!priv->enslaved) { + if (!priv->is_enslaved) { if (success) { if (activating) { _LOGI (LOGD_DEVICE, "Activation: connection '%s' enslaved, continuing activation", @@ -1894,8 +2475,9 @@ nm_device_slave_notify_enslave (NMDevice *self, gboolean success) } else _LOGI (LOGD_DEVICE, "enslaved to %s", nm_device_get_iface (priv->master)); - priv->enslaved = TRUE; + priv->is_enslaved = TRUE; g_object_notify (G_OBJECT (self), NM_DEVICE_MASTER); + g_object_notify (G_OBJECT (priv->master), NM_DEVICE_SLAVES); } else if (activating) { _LOGW (LOGD_DEVICE, "Activation: connection '%s' could not be enslaved", nm_connection_get_id (connection)); @@ -1924,12 +2506,13 @@ static void nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection = nm_device_get_connection (self); + NMConnection *connection = nm_device_get_applied_connection (self); NMDeviceState new_state; const char *master_status; - if ( reason != NM_DEVICE_STATE_REASON_NONE - && priv->state > NM_DEVICE_STATE_DISCONNECTED + g_return_if_fail (priv->master); + + if ( priv->state > NM_DEVICE_STATE_DISCONNECTED && priv->state <= NM_DEVICE_STATE_ACTIVATED) { if (reason == NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED) { new_state = NM_DEVICE_STATE_FAILED; @@ -1947,14 +2530,13 @@ nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason) master_status); nm_device_queue_state (self, new_state, reason); - } else if (priv->master) - _LOGI (LOGD_DEVICE, "released from master %s", nm_device_get_iface (priv->master)); - else - _LOGD (LOGD_DEVICE, "released from master%s", priv->enslaved ? "" : " (was not enslaved)"); + } else + _LOGI (LOGD_DEVICE, "released from master device %s", nm_device_get_iface (priv->master)); - if (priv->enslaved) { - priv->enslaved = FALSE; + if (priv->is_enslaved) { + priv->is_enslaved = FALSE; g_object_notify (G_OBJECT (self), NM_DEVICE_MASTER); + g_object_notify (G_OBJECT (priv->master), NM_DEVICE_SLAVES); } } @@ -1968,7 +2550,7 @@ nm_device_slave_notify_release (NMDevice *self, NMDeviceStateReason reason) gboolean nm_device_get_enslaved (NMDevice *self) { - return NM_DEVICE_GET_PRIVATE (self)->enslaved; + return NM_DEVICE_GET_PRIVATE (self)->is_enslaved; } /** @@ -1981,12 +2563,17 @@ nm_device_get_enslaved (NMDevice *self) void nm_device_removed (NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv; - if (priv->enslaved) - nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_REMOVED); -} + g_return_if_fail (NM_IS_DEVICE (self)); + priv = NM_DEVICE_GET_PRIVATE (self); + if (priv->master) { + /* this is called when something externally messes with the slave or during shut-down. + * Release the slave from master, but don't touch the device. */ + nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + } +} static gboolean is_available (NMDevice *self, NMDeviceCheckDevAvailableFlags flags) @@ -1996,7 +2583,7 @@ is_available (NMDevice *self, NMDeviceCheckDevAvailableFlags flags) if (priv->carrier || priv->ignore_carrier) return TRUE; - if (NM_FLAGS_HAS (flags, NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER)) + if (NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER)) return TRUE; return FALSE; @@ -2068,7 +2655,7 @@ nm_device_get_autoconnect (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->autoconnect; } -static void +void nm_device_set_autoconnect (NMDevice *self, gboolean autoconnect) { NMDevicePrivate *priv; @@ -2116,7 +2703,11 @@ nm_device_autoconnect_allowed (NMDevice *self) GValue instance = G_VALUE_INIT; GValue retval = G_VALUE_INIT; - if (priv->state < NM_DEVICE_STATE_DISCONNECTED || !priv->autoconnect) + if (!priv->autoconnect) + return FALSE; + + /* Unrealized devices can always autoconnect. */ + if (nm_device_is_real (self) && priv->state < NM_DEVICE_STATE_DISCONNECTED) return FALSE; /* The 'autoconnect-allowed' signal is emitted on a device to allow @@ -2130,15 +2721,13 @@ nm_device_autoconnect_allowed (NMDevice *self) g_value_set_object (&instance, self); g_value_init (&retval, G_TYPE_BOOLEAN); - if (priv->autoconnect) - g_value_set_boolean (&retval, TRUE); - else - g_value_set_boolean (&retval, FALSE); + g_value_set_boolean (&retval, TRUE); /* Use g_signal_emitv() rather than g_signal_emit() to avoid the return * value being changed if no handlers are connected */ g_signal_emitv (&instance, signals[AUTOCONNECT_ALLOWED], 0, &retval); g_value_unset (&instance); + return g_value_get_boolean (&retval); } @@ -2199,7 +2788,7 @@ device_has_config (NMDevice *self) return TRUE; /* The existence of a software device is good enough. */ - if (nm_device_is_software (self)) + if (nm_device_is_software (self) && nm_device_is_real (self)) return TRUE; /* Slaves are also configured by definition */ @@ -2429,6 +3018,34 @@ nm_device_check_connection_compatible (NMDevice *self, NMConnection *connection) return NM_DEVICE_GET_CLASS (self)->check_connection_compatible (self, connection); } +gboolean +nm_device_check_slave_connection_compatible (NMDevice *self, NMConnection *slave) +{ + NMDevicePrivate *priv; + NMSettingConnection *s_con; + const char *connection_type, *slave_type; + + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail (NM_IS_CONNECTION (slave), FALSE); + + priv = NM_DEVICE_GET_PRIVATE (self); + + if (!priv->is_master) + return FALSE; + + /* All masters should have connection type set */ + connection_type = NM_DEVICE_GET_CLASS (self)->connection_type; + g_return_val_if_fail (connection_type, FALSE); + + s_con = nm_connection_get_setting_connection (slave); + g_assert (s_con); + slave_type = nm_setting_connection_get_slave_type (s_con); + if (!slave_type) + return FALSE; + + return strcmp (connection_type, slave_type) == 0; +} + /** * nm_device_can_assume_connections: * @self: #NMDevice instance @@ -2441,7 +3058,8 @@ nm_device_check_connection_compatible (NMDevice *self, NMConnection *connection) static gboolean nm_device_can_assume_connections (NMDevice *self) { - return !!NM_DEVICE_GET_CLASS (self)->update_connection; + return !!NM_DEVICE_GET_CLASS (self)->update_connection + && !NM_DEVICE_GET_PRIVATE (self)->is_nm_owned; } /** @@ -2481,7 +3099,7 @@ nm_device_can_assume_active_connection (NMDevice *self) if (!nm_device_can_assume_connections (self)) return FALSE; - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); if (!connection) return FALSE; @@ -2505,9 +3123,14 @@ nm_device_can_assume_active_connection (NMDevice *self) } static gboolean -nm_device_emit_recheck_assume (gpointer self) +nm_device_emit_recheck_assume (gpointer user_data) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevice *self = user_data; + NMDevicePrivate *priv; + + g_return_val_if_fail (NM_IS_DEVICE (self), G_SOURCE_REMOVE); + + priv = NM_DEVICE_GET_PRIVATE (self); priv->recheck_assume_id = 0; if (!nm_device_get_act_request (self)) { @@ -2522,7 +3145,8 @@ nm_device_queue_recheck_assume (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (nm_device_can_assume_connections (self) && !priv->recheck_assume_id) + if ( !priv->recheck_assume_id + && nm_device_can_assume_connections (self)) priv->recheck_assume_id = g_idle_add (nm_device_emit_recheck_assume, self); } @@ -2544,13 +3168,17 @@ recheck_available (gpointer user_data) new_state = NM_DEVICE_STATE_UNAVAILABLE; nm_device_queue_state (self, new_state, priv->recheck_available.unavailable_reason); } - _LOGD (LOGD_DEVICE, "device is %savailable, %s %s", - now_available ? "" : "not ", - new_state == NM_DEVICE_STATE_UNAVAILABLE ? "no change required for" : "will transition to", - state_to_string (new_state == NM_DEVICE_STATE_UNAVAILABLE ? state : new_state)); - priv->recheck_available.available_reason = NM_DEVICE_STATE_REASON_NONE; - priv->recheck_available.unavailable_reason = NM_DEVICE_STATE_REASON_NONE; + if (new_state > NM_DEVICE_STATE_UNKNOWN) { + _LOGD (LOGD_DEVICE, "device is %savailable, %s %s", + now_available ? "" : "not ", + new_state == NM_DEVICE_STATE_UNAVAILABLE ? "no change required for" : "will transition to", + state_to_string (new_state == NM_DEVICE_STATE_UNAVAILABLE ? state : new_state)); + + priv->recheck_available.available_reason = NM_DEVICE_STATE_REASON_NONE; + priv->recheck_available.unavailable_reason = NM_DEVICE_STATE_REASON_NONE; + } + return G_SOURCE_REMOVE; } @@ -2587,63 +3215,119 @@ dnsmasq_state_changed_cb (NMDnsMasqManager *manager, guint32 status, gpointer us } } -static void -activation_source_clear (NMDevice *self, gboolean remove_source, int family) +/*****************************************************************************/ + +static gboolean +activation_source_handle_cb4 (gpointer user_data) +{ + activation_source_handle_cb (user_data, AF_INET); + return G_SOURCE_REMOVE; +} + +static gboolean +activation_source_handle_cb6 (gpointer user_data) +{ + activation_source_handle_cb (user_data, AF_INET6); + return G_SOURCE_REMOVE; +} + +static ActivationHandleData * +activation_source_get_by_family (NMDevice *self, + int family, + GSourceFunc *out_idle_func) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - guint *act_source_id; - gpointer *act_source_func; if (family == AF_INET6) { - act_source_id = &priv->act_source6_id; - act_source_func = &priv->act_source6_func; + NM_SET_OUT (out_idle_func, activation_source_handle_cb6); + return &priv->act_handle6; } else { - act_source_id = &priv->act_source_id; - act_source_func = &priv->act_source_func; + NM_SET_OUT (out_idle_func, activation_source_handle_cb4); + g_return_val_if_fail (family == AF_INET, &priv->act_handle4); + return &priv->act_handle4; } +} - if (*act_source_id) { - if (remove_source) - g_source_remove (*act_source_id); - *act_source_id = 0; - *act_source_func = NULL; +static void +activation_source_clear (NMDevice *self, int family) +{ + ActivationHandleData *act_data; + + act_data = activation_source_get_by_family (self, family, NULL); + + if (act_data->id) { + _LOGD (LOGD_DEVICE, "activation-stage: clear %s,%d (id %u)", + _activation_func_to_string (act_data->func), family, act_data->id); + nm_clear_g_source (&act_data->id); + act_data->func = NULL; } } static void -activation_source_schedule (NMDevice *self, GSourceFunc func, int family) +activation_source_handle_cb (NMDevice *self, int family) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - guint *act_source_id; - gpointer *act_source_func; + ActivationHandleData *act_data, a; - if (family == AF_INET6) { - act_source_id = &priv->act_source6_id; - act_source_func = &priv->act_source6_func; - } else { - act_source_id = &priv->act_source_id; - act_source_func = &priv->act_source_func; + g_return_if_fail (NM_IS_DEVICE (self)); + + act_data = activation_source_get_by_family (self, family, NULL); + + g_return_if_fail (act_data->id); + g_return_if_fail (act_data->func); + + a = *act_data; + + act_data->func = NULL; + act_data->id = 0; + + _LOGD (LOGD_DEVICE, "activation-stage: invoke %s,%d (id %u)", + _activation_func_to_string (a.func), family, a.id); + + a.func (self); + + _LOGD (LOGD_DEVICE, "activation-stage: complete %s,%d (id %u)", + _activation_func_to_string (a.func), family, a.id); +} + +static void +activation_source_schedule (NMDevice *self, ActivationHandleFunc func, int family) +{ + ActivationHandleData *act_data; + GSourceFunc source_func; + guint new_id = 0; + + act_data = activation_source_get_by_family (self, family, &source_func); + + if (act_data->id && act_data->func != func) { + /* Don't bother rescheduling the same function that's about to + * run anyway. Fixes issues with crappy wireless drivers sending + * streams of associate events before NM has had a chance to process + * the first one. + */ + _LOGD (LOGD_DEVICE, "activation-stage: already scheduled %s,%d (id %u)", + _activation_func_to_string (func), family, act_data->id); + return; } - if (*act_source_id) { - if (*act_source_func == func) { - /* Don't bother rescheduling the same function that's about to - * run anyway. Fixes issues with crappy wireless drivers sending - * streams of associate events before NM has had a chance to process - * the first one. - */ - _LOGD (LOGD_DEVICE, "activation stage already scheduled"); - return; - } else { - _LOGW (LOGD_DEVICE, "a different activation stage already scheduled"); - activation_source_clear (self, TRUE, family); - } + new_id = g_idle_add (source_func, self); + + if (act_data->id) { + _LOGW (LOGD_DEVICE, "activation-stage: schedule %s,%d which replaces %s,%d (id %u -> %u)", + _activation_func_to_string (func), family, + _activation_func_to_string (act_data->func), family, + act_data->id, new_id); + nm_clear_g_source (&act_data->id); + } else { + _LOGD (LOGD_DEVICE, "activation-stage: schedule %s,%d (id %u)", + _activation_func_to_string (func), family, new_id); } - *act_source_id = g_idle_add (func, self); - *act_source_func = func; + act_data->func = func; + act_data->id = new_id; } +/*****************************************************************************/ + static gboolean get_ip_config_may_fail (NMDevice *self, int family) { @@ -2652,7 +3336,7 @@ get_ip_config_may_fail (NMDevice *self, int family) g_return_val_if_fail (self != NULL, TRUE); - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); g_assert (connection); /* Fail the connection if the failed IP method is required to complete */ @@ -2675,26 +3359,31 @@ master_ready (NMDevice *self, NMActiveConnection *active) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMActiveConnection *master; + NMActiveConnection *master_connection; + NMDevice *master; g_return_if_fail (priv->state == NM_DEVICE_STATE_PREPARE); g_return_if_fail (!priv->master_ready_handled); /* Notify a master device that it has a new slave */ g_return_if_fail (nm_active_connection_get_master_ready (active)); - master = nm_active_connection_get_master (active); + master_connection = nm_active_connection_get_master (active); priv->master_ready_handled = TRUE; nm_clear_g_signal_handler (active, &priv->master_ready_id); - priv->master = g_object_ref (nm_active_connection_get_device (master)); - nm_device_master_add_slave (priv->master, - self, - nm_active_connection_get_assumed (active) ? FALSE : TRUE); + master = nm_active_connection_get_device (master_connection); _LOGD (LOGD_DEVICE, "master connection ready; master device %s", - nm_device_get_iface (priv->master)); + nm_device_get_iface (master)); + + if (priv->master && priv->master != master) + nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + /* If the master didn't change, add-slave only rechecks whether to assume a connection. */ + nm_device_master_add_slave (master, + self, + nm_active_connection_get_assumed (active) ? FALSE : TRUE); } static void @@ -2706,6 +3395,45 @@ master_ready_cb (NMActiveConnection *active, nm_device_activate_schedule_stage2_device_config (self); } +static void +lldp_neighbors_changed (NMLldpListener *lldp_listener, GParamSpec *pspec, + gpointer user_data) +{ + NMDevice *self = NM_DEVICE (user_data); + + g_object_notify (G_OBJECT (self), NM_DEVICE_LLDP_NEIGHBORS); +} + +static gboolean +lldp_rx_enabled (NMDevice *self) +{ + NMConnection *connection; + NMSettingConnection *s_con; + NMSettingConnectionLldp lldp = NM_SETTING_CONNECTION_LLDP_DEFAULT; + + connection = nm_device_get_applied_connection (self); + g_return_val_if_fail (connection, FALSE); + + s_con = nm_connection_get_setting_connection (connection); + g_return_val_if_fail (s_con, FALSE); + + lldp = nm_setting_connection_get_lldp (s_con); + if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT) { + gs_free char *value = NULL; + + value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "connection.lldp", + self); + lldp = _nm_utils_ascii_str_to_int64 (value, 10, + NM_SETTING_CONNECTION_LLDP_DEFAULT, + NM_SETTING_CONNECTION_LLDP_ENABLE_RX, + NM_SETTING_CONNECTION_LLDP_DEFAULT); + if (lldp == NM_SETTING_CONNECTION_LLDP_DEFAULT) + lldp = NM_SETTING_CONNECTION_LLDP_DISABLE; + } + return lldp == NM_SETTING_CONNECTION_LLDP_ENABLE_RX; +} + static NMActStageReturn act_stage1_prepare (NMDevice *self, NMDeviceStateReason *reason) { @@ -2713,48 +3441,39 @@ act_stage1_prepare (NMDevice *self, NMDeviceStateReason *reason) } /* - * nm_device_activate_stage1_device_prepare + * activate_stage1_device_prepare * * Prepare for device activation * */ -static gboolean -nm_device_activate_stage1_device_prepare (gpointer user_data) +static void +activate_stage1_device_prepare (NMDevice *self) { - NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request); - /* Clear the activation source ID now that this stage has run */ - activation_source_clear (self, FALSE, 0); - priv->ip4_state = priv->ip6_state = IP_NONE; /* Notify the new ActiveConnection along with the state change */ g_object_notify (G_OBJECT (self), NM_DEVICE_ACTIVE_CONNECTION); - _LOGD (LOGD_DEVICE, "Activation: Stage 1 of 5 (Device Prepare) started..."); nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE); /* Assumed connections were already set up outside NetworkManager */ if (!nm_active_connection_get_assumed (active)) { ret = NM_DEVICE_GET_CLASS (self)->act_stage1_prepare (self, &reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) { - goto out; + return; } else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); - goto out; + return; } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); } nm_device_activate_schedule_stage2_device_config (self); - -out: - _LOGD (LOGD_DEVICE, "Activation: Stage 1 of 5 (Device Prepare) complete."); - return FALSE; } @@ -2774,9 +3493,7 @@ nm_device_activate_schedule_stage1_device_prepare (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); g_return_if_fail (priv->act_request); - activation_source_schedule (self, nm_device_activate_stage1_device_prepare, 0); - - _LOGD (LOGD_DEVICE, "Activation: Stage 1 of 5 (Device Prepare) scheduled..."); + activation_source_schedule (self, activate_stage1_device_prepare, AF_INET); } static NMActStageReturn @@ -2787,16 +3504,15 @@ act_stage2_config (NMDevice *self, NMDeviceStateReason *reason) } /* - * nm_device_activate_stage2_device_config + * activate_stage2_device_config * * Determine device parameters and set those on the device, ie * for wireless devices, set SSID, keys, etc. * */ -static gboolean -nm_device_activate_stage2_device_config (gpointer user_data) +static void +activate_stage2_device_config (NMDevice *self) { - NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActStageReturn ret; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; @@ -2804,10 +3520,6 @@ nm_device_activate_stage2_device_config (gpointer user_data) NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request); GSList *iter; - /* Clear the activation source ID now that this stage has run */ - activation_source_clear (self, FALSE, 0); - - _LOGD (LOGD_DEVICE, "Activation: Stage 2 of 5 (Device Configure) starting..."); nm_device_state_changed (self, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE); /* Assumed connections were already set up outside NetworkManager */ @@ -2817,15 +3529,15 @@ nm_device_activate_stage2_device_config (gpointer user_data) nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_FIRMWARE_MISSING); else nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - goto out; + return; } ret = NM_DEVICE_GET_CLASS (self)->act_stage2_config (self, &reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) - goto out; + return; else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); - goto out; + return; } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); } @@ -2836,19 +3548,39 @@ nm_device_activate_stage2_device_config (gpointer user_data) NMDeviceState slave_state = nm_device_get_state (info->slave); if (slave_state == NM_DEVICE_STATE_IP_CONFIG) - nm_device_enslave_slave (self, info->slave, nm_device_get_connection (info->slave)); + nm_device_master_enslave_slave (self, info->slave, nm_device_get_applied_connection (info->slave)); else if ( nm_device_uses_generated_assumed_connection (self) && slave_state <= NM_DEVICE_STATE_DISCONNECTED) nm_device_queue_recheck_assume (info->slave); } - _LOGD (LOGD_DEVICE, "Activation: Stage 2 of 5 (Device Configure) successful."); + if (lldp_rx_enabled (self)) { + gs_free_error GError *error = NULL; + gconstpointer addr; + size_t addr_length; - nm_device_activate_schedule_stage3_ip_config_start (self); + if (priv->lldp_listener) + nm_lldp_listener_stop (priv->lldp_listener); + else { + priv->lldp_listener = nm_lldp_listener_new (); + g_signal_connect (priv->lldp_listener, + "notify::" NM_LLDP_LISTENER_NEIGHBORS, + G_CALLBACK (lldp_neighbors_changed), + self); + } -out: - _LOGD (LOGD_DEVICE, "Activation: Stage 2 of 5 (Device Configure) complete."); - return FALSE; + addr = nm_platform_link_get_address (NM_PLATFORM_GET, priv->ifindex, &addr_length); + + if (nm_lldp_listener_start (priv->lldp_listener, nm_device_get_ifindex (self), + nm_device_get_iface (self), addr, addr_length, &error)) + _LOGD (LOGD_DEVICE, "LLDP listener %p started", priv->lldp_listener); + else { + _LOGD (LOGD_DEVICE, "LLDP listener %p could not be started: %s", + priv->lldp_listener, error->message); + } + } + + nm_device_activate_schedule_stage3_ip_config_start (self); } @@ -2893,56 +3625,74 @@ nm_device_activate_schedule_stage2_device_config (NMDevice *self) } } - activation_source_schedule (self, nm_device_activate_stage2_device_config, 0); - - _LOGD (LOGD_DEVICE, "Activation: Stage 2 of 5 (Device Configure) scheduled..."); + activation_source_schedule (self, activate_stage2_device_config, AF_INET); } -/*********************************************/ -/* avahi-autoipd stuff */ - +/* + * nm_device_check_ip_failed + * + * Progress the device to appropriate state if both IPv4 and IPv6 failed + */ static void -aipd_timeout_remove (NMDevice *self) +nm_device_check_ip_failed (NMDevice *self, gboolean may_fail) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDeviceState state; + + if ( priv->ip4_state != IP_FAIL + || priv->ip6_state != IP_FAIL) + return; - if (priv->aipd_timeout) { - g_source_remove (priv->aipd_timeout); - priv->aipd_timeout = 0; + if (nm_device_uses_assumed_connection (self)) { + /* We have assumed configuration, but couldn't + * redo it. No problem, move to check state. */ + priv->ip4_state = priv->ip6_state = IP_DONE; + state = NM_DEVICE_STATE_IP_CHECK; + } else if ( may_fail + && get_ip_config_may_fail (self, AF_INET) + && get_ip_config_may_fail (self, AF_INET6)) { + /* Couldn't start either IPv6 and IPv4 autoconfiguration, + * but both are allowed to fail. */ + state = NM_DEVICE_STATE_SECONDARIES; + } else { + /* Autoconfiguration attempted without success. */ + state = NM_DEVICE_STATE_FAILED; } + + nm_device_state_changed (self, + state, + NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); } +/*********************************************/ +/* IPv4LL stuff */ + static void -aipd_cleanup (NMDevice *self) +ipv4ll_cleanup (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->aipd_watch) { - g_source_remove (priv->aipd_watch); - priv->aipd_watch = 0; - } - - if (priv->aipd_pid > 0) { - nm_utils_kill_child_sync (priv->aipd_pid, SIGKILL, LOGD_AUTOIP4, "avahi-autoipd", NULL, 0, 0); - priv->aipd_pid = -1; + if (priv->ipv4ll) { + sd_ipv4ll_set_callback (priv->ipv4ll, NULL, NULL); + sd_ipv4ll_stop (priv->ipv4ll); + priv->ipv4ll = sd_ipv4ll_unref (priv->ipv4ll); } - aipd_timeout_remove (self); + nm_clear_g_source (&priv->ipv4ll_timeout); } static NMIP4Config * -aipd_get_ip4_config (NMDevice *self, guint32 lla) +ipv4ll_get_ip4_config (NMDevice *self, guint32 lla) { NMIP4Config *config = NULL; NMPlatformIP4Address address; NMPlatformIP4Route route; - config = nm_ip4_config_new (); + config = nm_ip4_config_new (nm_device_get_ip_ifindex (self)); g_assert (config); memset (&address, 0, sizeof (address)); - address.address = lla; - address.plen = 16; + nm_platform_ip4_address_set_addr (&address, lla, 16); address.source = NM_IP_CONFIG_SOURCE_IP4LL; nm_ip4_config_add_address (config, &address); @@ -2960,22 +3710,21 @@ aipd_get_ip4_config (NMDevice *self, guint32 lla) #define IPV4LL_NETWORK (htonl (0xA9FE0000L)) #define IPV4LL_NETMASK (htonl (0xFFFF0000L)) -void -nm_device_handle_autoip4_event (NMDevice *self, - const char *event, - const char *address) +static void +nm_device_handle_ipv4ll_event (sd_ipv4ll *ll, int event, void *data) { + NMDevice *self = data; NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection = NULL; const char *method; - NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; - - g_return_if_fail (event != NULL); + struct in_addr address; + NMIP4Config *config; + int r; if (priv->act_request == NULL) return; - connection = nm_act_request_get_connection (priv->act_request); + connection = nm_act_request_get_applied_connection (priv->act_request); g_assert (connection); /* Ignore if the connection isn't an AutoIP connection */ @@ -2983,86 +3732,62 @@ nm_device_handle_autoip4_event (NMDevice *self, if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL) != 0) return; - if (strcmp (event, "BIND") == 0) { - guint32 lla; - NMIP4Config *config; - - if (inet_pton (AF_INET, address, &lla) <= 0) { - _LOGE (LOGD_AUTOIP4, "invalid address %s received from avahi-autoipd.", address); - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_AUTOIP_ERROR); + switch (event) { + case SD_IPV4LL_EVENT_BIND: + r = sd_ipv4ll_get_address (ll, &address); + if (r < 0) { + _LOGE (LOGD_AUTOIP4, "invalid IPv4 link-local address received, error %d.", r); + priv->ip4_state = IP_FAIL; + nm_device_check_ip_failed (self, FALSE); return; } - if ((lla & IPV4LL_NETMASK) != IPV4LL_NETWORK) { - _LOGE (LOGD_AUTOIP4, "invalid address %s received from avahi-autoipd (not link-local).", address); - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_AUTOIP_ERROR); + if ((address.s_addr & IPV4LL_NETMASK) != IPV4LL_NETWORK) { + _LOGE (LOGD_AUTOIP4, "invalid address %08x received (not link-local).", address.s_addr); + priv->ip4_state = IP_FAIL; + nm_device_check_ip_failed (self, FALSE); return; } - config = aipd_get_ip4_config (self, lla); + config = ipv4ll_get_ip4_config (self, address.s_addr); if (config == NULL) { - _LOGE (LOGD_AUTOIP4, "failed to get autoip config"); - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + _LOGE (LOGD_AUTOIP4, "failed to get IPv4LL config"); + priv->ip4_state = IP_FAIL; + nm_device_check_ip_failed (self, FALSE); return; } if (priv->ip4_state == IP_CONF) { - aipd_timeout_remove (self); + nm_clear_g_source (&priv->ipv4ll_timeout); nm_device_activate_schedule_ip4_config_result (self, config); } else if (priv->ip4_state == IP_DONE) { - if (!ip4_config_merge_and_apply (self, config, TRUE, &reason)) { + if (!ip4_config_merge_and_apply (self, config, TRUE, NULL)) { _LOGE (LOGD_AUTOIP4, "failed to update IP4 config for autoip change."); - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + priv->ip4_state = IP_FAIL; + nm_device_check_ip_failed (self, FALSE); } } else g_assert_not_reached (); g_object_unref (config); - } else { - _LOGW (LOGD_AUTOIP4, "autoip address %s no longer valid because '%s'.", address, event); - - /* The address is gone; terminate the connection or fail activation */ - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); + break; + default: + _LOGW (LOGD_AUTOIP4, "IPv4LL address no longer valid after event %d.", event); + priv->ip4_state = IP_FAIL; + nm_device_check_ip_failed (self, FALSE); } } -static void -aipd_watch_cb (GPid pid, gint status, gpointer user_data) -{ - NMDevice *self = NM_DEVICE (user_data); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceState state; - - if (!priv->aipd_watch) - return; - priv->aipd_watch = 0; - - if (WIFEXITED (status)) - _LOGD (LOGD_AUTOIP4, "avahi-autoipd exited with error code %d", WEXITSTATUS (status)); - else if (WIFSTOPPED (status)) - _LOGW (LOGD_AUTOIP4, "avahi-autoipd stopped unexpectedly with signal %d", WSTOPSIG (status)); - else if (WIFSIGNALED (status)) - _LOGW (LOGD_AUTOIP4, "avahi-autoipd died with signal %d", WTERMSIG (status)); - else - _LOGW (LOGD_AUTOIP4, "avahi-autoipd died from an unknown cause"); - - aipd_cleanup (self); - - state = nm_device_get_state (self); - if (nm_device_is_activating (self) || (state == NM_DEVICE_STATE_ACTIVATED)) - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); -} - static gboolean -aipd_timeout_cb (gpointer user_data) +ipv4ll_timeout_cb (gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->aipd_timeout) { - _LOGI (LOGD_AUTOIP4, "avahi-autoipd timed out."); - priv->aipd_timeout = 0; - aipd_cleanup (self); + if (priv->ipv4ll_timeout) { + _LOGI (LOGD_AUTOIP4, "IPv4LL configuration timed out."); + priv->ipv4ll_timeout = 0; + ipv4ll_cleanup (self); if (priv->ip4_state == IP_CONF) nm_device_activate_schedule_ip4_config_timeout (self); @@ -3071,66 +3796,68 @@ aipd_timeout_cb (gpointer user_data) return FALSE; } -/* default to installed helper, but can be modified for testing */ -const char *nm_device_autoipd_helper_path = LIBEXECDIR "/nm-avahi-autoipd.action"; - static NMActStageReturn -aipd_start (NMDevice *self, NMDeviceStateReason *reason) +ipv4ll_start (NMDevice *self, NMDeviceStateReason *reason) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const char *argv[6]; - char *cmdline; - const char *aipd_binary; - int i = 0; - GError *error = NULL; + const struct ether_addr *addr; + int ifindex, r; + size_t addr_len; - aipd_cleanup (self); + ipv4ll_cleanup (self); - /* Find avahi-autoipd */ - aipd_binary = nm_utils_find_helper ("avahi-autoipd", NULL, NULL); - if (!aipd_binary) { - _LOGW (LOGD_DEVICE | LOGD_AUTOIP4, - "Activation: Stage 3 of 5 (IP Configure Start) failed" - " to start avahi-autoipd: not found"); - *reason = NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; + r = sd_ipv4ll_new (&priv->ipv4ll); + if (r < 0) { + _LOGE (LOGD_AUTOIP4, "IPv4LL: new() failed with error %d", r); + goto fail; } - argv[i++] = aipd_binary; - argv[i++] = "--script"; - argv[i++] = nm_device_autoipd_helper_path; + r = sd_ipv4ll_attach_event (priv->ipv4ll, NULL, 0); + if (r < 0) { + _LOGE (LOGD_AUTOIP4, "IPv4LL: attach_event() failed with error %d", r); + goto fail; + } + + ifindex = nm_device_get_ip_ifindex (self); + addr = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &addr_len); + if (!addr || addr_len != ETH_ALEN) { + _LOGE (LOGD_AUTOIP4, "IPv4LL: can't retrieve hardware address"); + goto fail; + } - if (nm_logging_enabled (LOGL_DEBUG, LOGD_AUTOIP4)) - argv[i++] = "--debug"; - argv[i++] = nm_device_get_ip_iface (self); - argv[i++] = NULL; + r = sd_ipv4ll_set_mac (priv->ipv4ll, addr); + if (r < 0) { + _LOGE (LOGD_AUTOIP4, "IPv4LL: set_mac() failed with error %d", r); + goto fail; + } - cmdline = g_strjoinv (" ", (char **) argv); - _LOGD (LOGD_AUTOIP4, "running: %s", cmdline); - g_free (cmdline); + r = sd_ipv4ll_set_index (priv->ipv4ll, ifindex); + if (r < 0) { + _LOGE (LOGD_AUTOIP4, "IPv4LL: set_index() failed with error %d", r); + goto fail; + } - if (!g_spawn_async ("/", (char **) argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, - nm_utils_setpgid, NULL, &(priv->aipd_pid), &error)) { - _LOGW (LOGD_DEVICE | LOGD_AUTOIP4, - "Activation: Stage 3 of 5 (IP Configure Start) failed" - " to start avahi-autoipd: %s", - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - aipd_cleanup (self); - return NM_ACT_STAGE_RETURN_FAILURE; + r = sd_ipv4ll_set_callback (priv->ipv4ll, nm_device_handle_ipv4ll_event, self); + if (r < 0) { + _LOGE (LOGD_AUTOIP4, "IPv4LL: set_callback() failed with error %d", r); + goto fail; } - _LOGD (LOGD_DEVICE | LOGD_AUTOIP4, - "Activation: Stage 3 of 5 (IP Configure Start) started" - " avahi-autoipd..."); + r = sd_ipv4ll_start (priv->ipv4ll); + if (r < 0) { + _LOGE (LOGD_AUTOIP4, "IPv4LL: start() failed with error %d", r); + goto fail; + } - /* Monitor the child process so we know when it dies */ - priv->aipd_watch = g_child_watch_add (priv->aipd_pid, aipd_watch_cb, self); + _LOGI (LOGD_DEVICE | LOGD_AUTOIP4, "IPv4LL: started"); /* Start a timeout to bound the address attempt */ - priv->aipd_timeout = g_timeout_add_seconds (20, aipd_timeout_cb, self); + priv->ipv4ll_timeout = g_timeout_add_seconds (20, ipv4ll_timeout_cb, self); return NM_ACT_STAGE_RETURN_POSTPONE; +fail: + *reason = NM_DEVICE_STATE_REASON_AUTOIP_START_FAILED; + return NM_ACT_STAGE_RETURN_FAILURE; } /*********************************************/ @@ -3185,16 +3912,17 @@ static void ensure_con_ip4_config (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + int ip_ifindex = nm_device_get_ip_ifindex (self); NMConnection *connection; if (priv->con_ip4_config) return; - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); if (!connection) return; - priv->con_ip4_config = nm_ip4_config_new (); + priv->con_ip4_config = nm_ip4_config_new (ip_ifindex); nm_ip4_config_merge_setting (priv->con_ip4_config, nm_connection_get_setting_ip4_config (connection), nm_device_get_ip4_route_metric (self)); @@ -3210,16 +3938,17 @@ static void ensure_con_ip6_config (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + int ip_ifindex = nm_device_get_ip_ifindex (self); NMConnection *connection; if (priv->con_ip6_config) return; - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); if (!connection) return; - priv->con_ip6_config = nm_ip6_config_new (); + priv->con_ip6_config = nm_ip6_config_new (ip_ifindex); nm_ip6_config_merge_setting (priv->con_ip6_config, nm_connection_get_setting_ip6_config (connection), nm_device_get_ip6_route_metric (self)); @@ -3243,10 +3972,7 @@ dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) if (priv->dhcp4_client) { /* Stop any ongoing DHCP transaction on this device */ - if (priv->dhcp4_state_sigid) { - g_signal_handler_disconnect (priv->dhcp4_client, priv->dhcp4_state_sigid); - priv->dhcp4_state_sigid = 0; - } + nm_clear_g_signal_handler (priv->dhcp4_client, &priv->dhcp4_state_sigid); nm_device_remove_pending_action (self, PENDING_ACTION_DHCP4, FALSE); @@ -3258,11 +3984,20 @@ dhcp4_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) } if (priv->dhcp4_config) { - g_clear_object (&priv->dhcp4_config); + nm_exported_object_clear_and_unexport (&priv->dhcp4_config); g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP4_CONFIG); } } +static void +_ip4_config_merge_default (gpointer value, gpointer user_data) +{ + NMIP4Config *src = (NMIP4Config *) value; + NMIP4Config *dst = (NMIP4Config *) user_data; + + nm_ip4_config_merge (dst, src, NM_IP_CONFIG_MERGE_DEFAULT); +} + static gboolean ip4_config_merge_and_apply (NMDevice *self, NMIP4Config *config, @@ -3288,7 +4023,7 @@ ip4_config_merge_and_apply (NMDevice *self, } /* Apply ignore-auto-routes and ignore-auto-dns settings */ - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); if (connection) { NMSettingIPConfig *s_ip4 = nm_connection_get_setting_ip4_config (connection); @@ -3298,7 +4033,7 @@ ip4_config_merge_and_apply (NMDevice *self, } } - composite = nm_ip4_config_new (); + composite = nm_ip4_config_new (nm_device_get_ip_ifindex (self)); if (commit) ensure_con_ip4_config (self); @@ -3308,8 +4043,9 @@ ip4_config_merge_and_apply (NMDevice *self, (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0)); } - if (priv->vpn4_config) - nm_ip4_config_merge (composite, priv->vpn4_config, NM_IP_CONFIG_MERGE_DEFAULT); + + g_slist_foreach (priv->vpn4_configs, _ip4_config_merge_default, composite); + if (priv->ext_ip4_config) nm_ip4_config_merge (composite, priv->ext_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT); @@ -3327,7 +4063,6 @@ ip4_config_merge_and_apply (NMDevice *self, if (priv->con_ip4_config) nm_ip4_config_merge (composite, priv->con_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT); - /* Add the default route. * * We keep track of the default route of a device in a private field. @@ -3366,7 +4101,7 @@ ip4_config_merge_and_apply (NMDevice *self, if ( !priv->v4_commit_first_time && connection_is_never_default) { - /* If the connection is explicitly configured as never-default, we enforce the (absense of the) + /* If the connection is explicitly configured as never-default, we enforce the (absence of the) * default-route only once. That allows the user to configure a connection as never-default, * but he can add default routes externally (via a dispatcher script) and NM will not interfere. */ goto END_ADD_DEFAULT_ROUTE; @@ -3390,7 +4125,7 @@ ip4_config_merge_and_apply (NMDevice *self, goto END_ADD_DEFAULT_ROUTE; has_direct_route = ( gateway == 0 - || nm_ip4_config_get_subnet_for_host (composite, gateway) + || nm_ip4_config_destination_is_direct (composite, gateway, 32) || nm_ip4_config_get_direct_route_for_host (composite, gateway)); priv->default_route.v4_has = TRUE; @@ -3452,7 +4187,8 @@ dhcp4_lease_change (NMDevice *self, NMIP4Config *config) } else { /* Notify dispatcher scripts of new DHCP4 config */ nm_dispatcher_call (DISPATCHER_ACTION_DHCP4_CHANGE, - nm_device_get_connection (self), + nm_device_get_settings_connection (self), + nm_device_get_applied_connection (self), self, NULL, NULL, @@ -3472,7 +4208,7 @@ dhcp4_restart_cb (gpointer user_data) priv = NM_DEVICE_GET_PRIVATE (self); priv->dhcp4_restart_id = 0; - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); if (dhcp4_start (self, connection, &reason) == NM_ACT_STAGE_RETURN_FAILURE) priv->dhcp4_restart_id = g_timeout_add_seconds (120, dhcp4_restart_cb, self); @@ -3516,22 +4252,6 @@ dhcp4_fail (NMDevice *self, gboolean timeout) g_warn_if_reached (); } -static void -dhcp4_update_config (NMDevice *self, NMDhcp4Config *config, GHashTable *options) -{ - GHashTableIter iter; - const char *key, *value; - - /* Update the DHCP4 config object with new DHCP options */ - nm_dhcp4_config_reset (config); - - g_hash_table_iter_init (&iter, options); - while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value)) - nm_dhcp4_config_add_option (config, key, value); - - g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP4_CONFIG); -} - static void dhcp4_state_changed (NMDhcpClient *client, NMDhcpState state, @@ -3558,7 +4278,8 @@ dhcp4_state_changed (NMDhcpClient *client, break; } - dhcp4_update_config (self, priv->dhcp4_config, options); + nm_dhcp4_config_set_options (priv->dhcp4_config, options); + g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP4_CONFIG); if (priv->ip4_state == IP_CONF) nm_device_activate_schedule_ip4_config_result (self, ip4_config); @@ -3584,6 +4305,28 @@ dhcp4_state_changed (NMDhcpClient *client, } } +static int +dhcp4_get_timeout (NMDevice *self, NMSettingIP4Config *s_ip4) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gs_free char *value = NULL; + int timeout; + + timeout = nm_setting_ip4_config_get_dhcp_timeout (s_ip4); + if (timeout) + return timeout; + + value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "ipv4.dhcp-timeout", + self); + timeout = _nm_utils_ascii_str_to_int64 (value, 10, + 0, G_MAXINT32, 0); + if (timeout) + return timeout; + + return priv->dhcp_timeout; +} + static NMActStageReturn dhcp4_start (NMDevice *self, NMConnection *connection, @@ -3598,8 +4341,7 @@ dhcp4_start (NMDevice *self, s_ip4 = nm_connection_get_setting_ip4_config (connection); /* Clear old exported DHCP options */ - if (priv->dhcp4_config) - g_object_unref (priv->dhcp4_config); + nm_exported_object_clear_and_unexport (&priv->dhcp4_config); priv->dhcp4_config = nm_dhcp4_config_new (); hw_addr = nm_platform_link_get_address (NM_PLATFORM_GET, nm_device_get_ip_ifindex (self), &hw_addr_len); @@ -3618,8 +4360,9 @@ dhcp4_start (NMDevice *self, nm_device_get_ip4_route_metric (self), nm_setting_ip_config_get_dhcp_send_hostname (s_ip4), nm_setting_ip_config_get_dhcp_hostname (s_ip4), + nm_setting_ip4_config_get_dhcp_fqdn (NM_SETTING_IP4_CONFIG (s_ip4)), nm_setting_ip4_config_get_dhcp_client_id (NM_SETTING_IP4_CONFIG (s_ip4)), - priv->dhcp_timeout, + dhcp4_get_timeout (self, NM_SETTING_IP4_CONFIG (s_ip4)), priv->dhcp_anycast_address, NULL); @@ -3657,7 +4400,7 @@ nm_device_dhcp4_renew (NMDevice *self, gboolean release) /* Terminate old DHCP instance and release the old lease */ dhcp4_cleanup (self, CLEANUP_TYPE_DECONFIGURE, release); - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); g_assert (connection); /* Start DHCP again on the interface */ @@ -3687,10 +4430,11 @@ reserve_shared_ip (NMDevice *self, NMSettingIPConfig *s_ip4, NMPlatformIP4Addres if (s_ip4 && nm_setting_ip_config_get_num_addresses (s_ip4)) { /* Use the first user-supplied address */ NMIPAddress *user = nm_setting_ip_config_get_address (s_ip4, 0); + in_addr_t a; g_assert (user); - nm_ip_address_get_address_binary (user, &address->address); - address->plen = nm_ip_address_get_prefix (user); + nm_ip_address_get_address_binary (user, &a); + nm_platform_ip4_address_set_addr (address, a, nm_ip_address_get_prefix (user)); } else { /* Find an unused address in the 10.42.x.x range */ guint32 start = (guint32) ntohl (0x0a2a0001); /* 10.42.0.1 */ @@ -3703,8 +4447,7 @@ reserve_shared_ip (NMDevice *self, NMSettingIPConfig *s_ip4, NMPlatformIP4Addres return FALSE; } } - address->address = start + count; - address->plen = 24; + nm_platform_ip4_address_set_addr (address, start + count, 24); g_hash_table_insert (shared_ips, GUINT_TO_POINTER (address->address), @@ -3727,7 +4470,7 @@ shared4_new_config (NMDevice *self, NMConnection *connection, NMDeviceStateReaso return NULL; } - config = nm_ip4_config_new (); + config = nm_ip4_config_new (nm_device_get_ip_ifindex (self)); address.source = NM_IP_CONFIG_SOURCE_SHARED; nm_ip4_config_add_address (config, &address); @@ -3852,7 +4595,7 @@ act_stage3_ip4_config_start (NMDevice *self, g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); g_assert (connection); if ( connection_ip4_method_requires_carrier (connection, NULL) @@ -3884,10 +4627,10 @@ act_stage3_ip4_config_start (NMDevice *self, if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0) ret = dhcp4_start (self, connection, reason); else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL) == 0) - ret = aipd_start (self, reason); + ret = ipv4ll_start (self, reason); else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL) == 0) { /* Use only IPv4 config from the connection data */ - *out_config = nm_ip4_config_new (); + *out_config = nm_ip4_config_new (nm_device_get_ip_ifindex (self)); g_assert (*out_config); ret = NM_ACT_STAGE_RETURN_SUCCESS; } else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED) == 0) { @@ -3917,14 +4660,10 @@ dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) priv->dhcp6_mode = NM_RDISC_DHCP_LEVEL_NONE; g_clear_object (&priv->dhcp6_ip6_config); g_clear_pointer (&priv->dhcp6_event_id, g_free); - nm_clear_g_source (&priv->dhcp6_restart_id); if (priv->dhcp6_client) { - if (priv->dhcp6_state_sigid) { - g_signal_handler_disconnect (priv->dhcp6_client, priv->dhcp6_state_sigid); - priv->dhcp6_state_sigid = 0; - } + nm_clear_g_signal_handler (priv->dhcp6_client, &priv->dhcp6_state_sigid); if ( cleanup_type == CLEANUP_TYPE_DECONFIGURE || cleanup_type == CLEANUP_TYPE_REMOVED) @@ -3936,11 +4675,20 @@ dhcp6_cleanup (NMDevice *self, CleanupType cleanup_type, gboolean release) nm_device_remove_pending_action (self, PENDING_ACTION_DHCP6, FALSE); if (priv->dhcp6_config) { - g_clear_object (&priv->dhcp6_config); + nm_exported_object_clear_and_unexport (&priv->dhcp6_config); g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP6_CONFIG); } } +static void +_ip6_config_merge_default (gpointer value, gpointer user_data) +{ + NMIP6Config *src = (NMIP6Config *) value; + NMIP6Config *dst = (NMIP6Config *) user_data; + + nm_ip6_config_merge (dst, src, NM_IP_CONFIG_MERGE_DEFAULT); +} + static gboolean ip6_config_merge_and_apply (NMDevice *self, gboolean commit, @@ -3958,7 +4706,7 @@ ip6_config_merge_and_apply (NMDevice *self, gboolean ignore_auto_dns = FALSE; /* Apply ignore-auto-routes and ignore-auto-dns settings */ - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); if (connection) { NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection); @@ -3969,10 +4717,11 @@ ip6_config_merge_and_apply (NMDevice *self, } /* If no config was passed in, create a new one */ - composite = nm_ip6_config_new (); + composite = nm_ip6_config_new (nm_device_get_ip_ifindex (self)); if (commit) ensure_con_ip6_config (self); + g_assert (composite); /* Merge all the IP configs into the composite config */ if (priv->ac_ip6_config) { @@ -3985,8 +4734,9 @@ ip6_config_merge_and_apply (NMDevice *self, (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0)); } - if (priv->vpn6_config) - nm_ip6_config_merge (composite, priv->vpn6_config, NM_IP_CONFIG_MERGE_DEFAULT); + + g_slist_foreach (priv->vpn6_configs, _ip6_config_merge_default, composite); + if (priv->ext_ip6_config) nm_ip6_config_merge (composite, priv->ext_ip6_config, NM_IP_CONFIG_MERGE_DEFAULT); @@ -4121,7 +4871,7 @@ static void dhcp6_lease_change (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMConnection *connection; + NMSettingsConnection *settings_connection; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; if (priv->dhcp6_ip6_config == NULL) { @@ -4132,8 +4882,8 @@ dhcp6_lease_change (NMDevice *self) g_assert (priv->dhcp6_client); /* sanity check */ - connection = nm_device_get_connection (self); - g_assert (connection); + settings_connection = nm_device_get_settings_connection (self); + g_assert (settings_connection); /* Apply the updated config */ if (ip6_config_merge_and_apply (self, TRUE, &reason) == FALSE) { @@ -4141,7 +4891,10 @@ dhcp6_lease_change (NMDevice *self) nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); } else { /* Notify dispatcher scripts of new DHCPv6 config */ - nm_dispatcher_call (DISPATCHER_ACTION_DHCP6_CHANGE, connection, self, NULL, NULL, NULL); + nm_dispatcher_call (DISPATCHER_ACTION_DHCP6_CHANGE, + settings_connection, + nm_device_get_applied_connection (self), + self, NULL, NULL, NULL); } } @@ -4220,22 +4973,6 @@ dhcp6_timeout (NMDevice *self, NMDhcpClient *client) } } -static void -dhcp6_update_config (NMDevice *self, NMDhcp6Config *config, GHashTable *options) -{ - GHashTableIter iter; - const char *key, *value; - - /* Update the DHCP6 config object with new DHCP options */ - nm_dhcp6_config_reset (config); - - g_hash_table_iter_init (&iter, options); - while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value)) - nm_dhcp6_config_add_option (config, key, value); - - g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP6_CONFIG); -} - static void dhcp6_state_changed (NMDhcpClient *client, NMDhcpState state, @@ -4273,7 +5010,7 @@ dhcp6_state_changed (NMDhcpClient *client, if (ip6_config) { priv->dhcp6_ip6_config = g_object_ref (ip6_config); priv->dhcp6_event_id = g_strdup (event_id); - dhcp6_update_config (self, priv->dhcp6_config, options); + nm_dhcp6_config_set_options (priv->dhcp6_config, options); g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP6_CONFIG); } } @@ -4320,6 +5057,9 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) GByteArray *tmp = NULL; const guint8 *hw_addr; size_t hw_addr_len = 0; + const struct in6_addr *ll_addr = NULL; + NMIP6Config *ip6_config; + int i; g_assert (connection); s_ip6 = nm_connection_get_setting_ip6_config (connection); @@ -4331,10 +5071,22 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection) g_byte_array_append (tmp, hw_addr, hw_addr_len); } + ip6_config = priv->ext_ip6_config; + for (i = 0; ip6_config && i < nm_ip6_config_get_num_addresses (ip6_config); i++) { + const NMPlatformIP6Address *addr = nm_ip6_config_get_address (ip6_config, i); + + if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) { + ll_addr = &addr->address; + break; + } + } + g_return_val_if_fail (ll_addr, FALSE); + priv->dhcp6_client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (), nm_device_get_ip_iface (self), nm_device_get_ip_ifindex (self), tmp, + ll_addr, nm_connection_get_uuid (connection), nm_device_get_ip6_route_metric (self), nm_setting_ip_config_get_dhcp_send_hostname (s_ip6), @@ -4363,14 +5115,14 @@ dhcp6_start (NMDevice *self, gboolean wait_for_ll, NMDeviceStateReason *reason) NMConnection *connection; NMSettingIPConfig *s_ip6; - g_clear_object (&priv->dhcp6_config); + nm_exported_object_clear_and_unexport (&priv->dhcp6_config); priv->dhcp6_config = nm_dhcp6_config_new (); g_warn_if_fail (priv->dhcp6_ip6_config == NULL); g_clear_object (&priv->dhcp6_ip6_config); g_clear_pointer (&priv->dhcp6_event_id, g_free); - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); g_assert (connection); s_ip6 = nm_connection_get_setting_ip6_config (connection); if (!nm_setting_ip_config_get_may_fail (s_ip6) || @@ -4443,10 +5195,14 @@ linklocal6_cleanup (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->linklocal6_timeout_id) { - g_source_remove (priv->linklocal6_timeout_id); - priv->linklocal6_timeout_id = 0; - } + nm_clear_g_source (&priv->linklocal6_timeout_id); +} + +static void +linklocal6_failed (NMDevice *self) +{ + linklocal6_cleanup (self); + nm_device_activate_schedule_ip6_config_timeout (self); } static gboolean @@ -4454,11 +5210,8 @@ linklocal6_timeout_cb (gpointer user_data) { NMDevice *self = user_data; - linklocal6_cleanup (self); - _LOGD (LOGD_DEVICE, "linklocal6: waiting for link-local addresses failed due to timeout"); - - nm_device_activate_schedule_ip6_config_timeout (self); + linklocal6_failed (self); return G_SOURCE_REMOVE; } @@ -4474,7 +5227,7 @@ linklocal6_complete (NMDevice *self) linklocal6_cleanup (self); - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); g_assert (connection); method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); @@ -4502,9 +5255,11 @@ check_and_add_ipv6ll_addr (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); int ip_ifindex = nm_device_get_ip_ifindex (self); - NMUtilsIPv6IfaceId iid; struct in6_addr lladdr; guint i, n; + NMConnection *connection; + NMSettingIP6Config *s_ip6 = NULL; + GError *error = NULL; if (priv->nm_ipv6ll == FALSE) return; @@ -4515,27 +5270,59 @@ check_and_add_ipv6ll_addr (NMDevice *self) const NMPlatformIP6Address *addr; addr = nm_ip6_config_get_address (priv->ip6_config, i); - if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) { + if ( IN6_IS_ADDR_LINKLOCAL (&addr->address) + && !(addr->flags & IFA_F_DADFAILED)) { /* Already have an LL address, nothing to do */ return; } } } - if (!nm_device_get_ip_iface_identifier (self, &iid)) { - _LOGW (LOGD_IP6, "failed to get interface identifier; IPv6 may be broken"); - return; - } - memset (&lladdr, 0, sizeof (lladdr)); lladdr.s6_addr16[0] = htons (0xfe80); - nm_utils_ipv6_addr_set_interface_identfier (&lladdr, iid); - _LOGD (LOGD_IP6, "adding IPv6LL address %s", nm_utils_inet6_ntop (&lladdr, NULL)); + + connection = nm_device_get_applied_connection (self); + if (connection) + s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection)); + + if (s_ip6 && nm_setting_ip6_config_get_addr_gen_mode (s_ip6) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) { + if (!nm_utils_ipv6_addr_set_stable_privacy (&lladdr, + nm_device_get_iface (self), + nm_connection_get_uuid (connection), + priv->linklocal6_dad_counter++, + &error)) { + _LOGW (LOGD_IP6, "linklocal6: failed to generate an address: %s", error->message); + g_clear_error (&error); + linklocal6_failed (self); + return; + } + _LOGD (LOGD_IP6, "linklocal6: using IPv6 stable-privacy addressing"); + } else { + NMUtilsIPv6IfaceId iid; + + if (priv->linklocal6_timeout_id) { + /* We already started and attempt to add a LL address. For the EUI-64 + * mode we can't pick a new one, we'll just fail. */ + _LOGW (LOGD_IP6, "linklocal6: DAD failed for an EUI-64 address"); + linklocal6_failed (self); + return; + } + + if (!nm_device_get_ip_iface_identifier (self, &iid)) { + _LOGW (LOGD_IP6, "linklocal6: failed to get interface identifier; IPv6 cannot continue"); + return; + } + _LOGD (LOGD_IP6, "linklocal6: using EUI-64 identifier to generate IPv6LL address"); + + nm_utils_ipv6_addr_set_interface_identfier (&lladdr, iid); + } + + _LOGD (LOGD_IP6, "linklocal6: adding IPv6LL address %s", nm_utils_inet6_ntop (&lladdr, NULL)); if (!nm_platform_ip6_address_add (NM_PLATFORM_GET, ip_ifindex, lladdr, - in6addr_any, 64, + in6addr_any, NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0)) { @@ -4556,7 +5343,7 @@ linklocal6_start (NMDevice *self) if (have_ip6_address (priv->ip6_config, TRUE)) return NM_ACT_STAGE_RETURN_FINISH; - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); g_assert (connection); method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); @@ -4576,53 +5363,6 @@ linklocal6_start (NMDevice *self) /******************************************/ -static void -print_support_extended_ifa_flags (NMSettingIP6ConfigPrivacy use_tempaddr) -{ - static gint8 warn = 0; - static gint8 s_libnl = -1, s_kernel; - - if (warn >= 2) - return; - - if (s_libnl == -1) { - s_libnl = !!nm_platform_check_support_libnl_extended_ifa_flags (); - s_kernel = !!nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET); - - if (s_libnl && s_kernel) { - nm_log_dbg (LOGD_IP6, "kernel and libnl support extended IFA_FLAGS (needed by NM for IPv6 private addresses)"); - warn = 2; - return; - } - } - - if ( use_tempaddr != NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR - && use_tempaddr != NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) { - if (warn == 0) { - nm_log_dbg (LOGD_IP6, "%s%s%s %s not support extended IFA_FLAGS (needed by NM for IPv6 private addresses)", - !s_kernel ? "kernel" : "", - !s_kernel && !s_libnl ? " and " : "", - !s_libnl ? "libnl" : "", - !s_kernel && !s_libnl ? "do" : "does"); - warn = 1; - } - return; - } - - if (!s_libnl && !s_kernel) { - nm_log_warn (LOGD_IP6, "libnl and the kernel do not support extended IFA_FLAGS needed by NM for " - "IPv6 private addresses. This feature is not available"); - } else if (!s_libnl) { - nm_log_warn (LOGD_IP6, "libnl does not support extended IFA_FLAGS needed by NM for " - "IPv6 private addresses. This feature is not available"); - } else if (!s_kernel) { - nm_log_warn (LOGD_IP6, "The kernel does not support extended IFA_FLAGS needed by NM for " - "IPv6 private addresses. This feature is not available"); - } - - warn = 2; -} - static void nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu); static void @@ -4680,24 +5420,20 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); int i; - static int system_support = -1; + int system_support; guint ifa_flags = 0x00; - if (system_support == -1) { - /* - * Check, if both libnl and the kernel are recent enough, - * to help user space handling RA. If it's not supported, - * we have no ipv6-privacy and must add autoconf addresses - * as /128. The reason for the /128 is to prevent the kernel - * from adding a prefix route for this address. - **/ - system_support = nm_platform_check_support_libnl_extended_ifa_flags () && - nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET); - } + /* + * Check, whether kernel is recent enough to help user space handling RA. + * If it's not supported, we have no ipv6-privacy and must add autoconf + * addresses as /128. The reason for the /128 is to prevent the kernel + * from adding a prefix route for this address. + **/ + system_support = nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET); if (system_support) ifa_flags = IFA_F_NOPREFIXROUTE; - if (priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR + if ( priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR || priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) { /* without system_support, this flag will be ignored. Still set it, doesn't seem to do any harm. */ @@ -4707,7 +5443,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self) g_return_if_fail (priv->act_request); if (!priv->ac_ip6_config) - priv->ac_ip6_config = nm_ip6_config_new (); + priv->ac_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self)); if (changed & NM_RDISC_CONFIG_GATEWAYS) { /* Use the first gateway as ordered in router discovery cache. */ @@ -4805,10 +5541,11 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self) "Activation: Stage 3 of 5 (IP Configure Start) starting DHCPv6" " as requested by IPv6 router..."); if (!dhcp6_start (self, FALSE, &reason)) { - if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_MANAGED) + if (priv->dhcp6_mode == NM_RDISC_DHCP_LEVEL_MANAGED) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); + return; + } } - return; } } @@ -4854,10 +5591,15 @@ addrconf6_start_with_link_ready (NMDevice *self) g_assert (priv->rdisc); if (nm_platform_link_get_ipv6_token (NM_PLATFORM_GET, priv->ifindex, &iid)) { - _LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface); - } else if (!nm_device_get_ip_iface_identifier (self, &iid)) { - _LOGW (LOGD_IP6, "failed to get interface identifier; IPv6 cannot continue"); - return FALSE; + _LOGD (LOGD_IP6, "addrconf6: IPv6 tokenized identifier present"); + nm_rdisc_set_iid (priv->rdisc, iid); + } else if (nm_device_get_ip_iface_identifier (self, &iid)) { + _LOGD (LOGD_IP6, "addrconf6: using the device EUI-64 identifier"); + nm_rdisc_set_iid (priv->rdisc, iid); + } else { + /* Don't abort the addrconf at this point -- if rdisc needs the iid + * it will notice this itself. */ + _LOGI (LOGD_IP6, "addrconf6: no interface identifier; IPv6 adddress creation may fail"); } /* Apply any manual configuration before starting RA */ @@ -4878,7 +5620,6 @@ addrconf6_start_with_link_ready (NMDevice *self) G_CALLBACK (rdisc_ra_timeout), self); - nm_rdisc_set_iid (priv->rdisc, iid); nm_rdisc_start (priv->rdisc); return TRUE; } @@ -4889,9 +5630,10 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection; NMActStageReturn ret; - const char *ip_iface = nm_device_get_ip_iface (self); + NMSettingIP6Config *s_ip6 = NULL; + GError *error = NULL; - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); g_assert (connection); g_warn_if_fail (priv->ac_ip6_config == NULL); @@ -4900,14 +5642,27 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr) priv->ac_ip6_config = NULL; } - priv->rdisc = nm_lndp_rdisc_new (nm_device_get_ip_ifindex (self), ip_iface); + s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection)); + g_assert (s_ip6); + + priv->rdisc = nm_lndp_rdisc_new (nm_device_get_ip_ifindex (self), + nm_device_get_ip_iface (self), + nm_connection_get_uuid (connection), + nm_setting_ip6_config_get_addr_gen_mode (s_ip6), + &error); if (!priv->rdisc) { - _LOGE (LOGD_IP6, "failed to start router discovery (%s)", ip_iface); + _LOGE (LOGD_IP6, "addrconf6: failed to start router discovery: %s", error->message); + g_error_free (error); return FALSE; } priv->rdisc_use_tempaddr = use_tempaddr; - print_support_extended_ifa_flags (use_tempaddr); + + if ( NM_IN_SET (use_tempaddr, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) + && !nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET)) { + _LOGW (LOGD_IP6, "The kernel does not support extended IFA_FLAGS needed by NM for " + "IPv6 private addresses. This feature is not available"); + } if (!nm_setting_ip_config_get_may_fail (nm_connection_get_setting_ip6_config (connection))) nm_device_add_pending_action (self, PENDING_ACTION_AUTOCONF6, TRUE); @@ -4929,15 +5684,8 @@ addrconf6_cleanup (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->rdisc_changed_id) { - g_signal_handler_disconnect (priv->rdisc, priv->rdisc_changed_id); - priv->rdisc_changed_id = 0; - } - - if (priv->rdisc_timeout_id) { - g_signal_handler_disconnect (priv->rdisc, priv->rdisc_timeout_id); - priv->rdisc_timeout_id = 0; - } + nm_clear_g_signal_handler (priv->rdisc, &priv->rdisc_changed_id); + nm_clear_g_signal_handler (priv->rdisc, &priv->rdisc_timeout_id); nm_device_remove_pending_action (self, PENDING_ACTION_AUTOCONF6, FALSE); @@ -5060,7 +5808,7 @@ _ip6_privacy_get (NMDevice *self) /* 1.) First look at the per-connection setting. If it is not -1 (unknown), * use it. */ - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); if (connection) { NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection); @@ -5126,7 +5874,7 @@ act_stage3_ip6_config_start (NMDevice *self, g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); g_assert (connection); if ( connection_ip6_method_requires_carrier (connection, NULL) @@ -5208,7 +5956,7 @@ act_stage3_ip6_config_start (NMDevice *self, ret = NM_ACT_STAGE_RETURN_POSTPONE; } else if (strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_MANUAL) == 0) { /* New blank config */ - *out_config = nm_ip6_config_new (); + *out_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self)); g_assert (*out_config); ret = NM_ACT_STAGE_RETURN_SUCCESS; @@ -5308,71 +6056,30 @@ nm_device_activate_stage3_ip6_start (NMDevice *self) priv->ip6_state = IP_DONE; if (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG) nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); - } else if (ret == NM_ACT_STAGE_RETURN_WAIT) { - /* Wait for something to try IP config again */ - priv->ip6_state = IP_WAIT; - } else - g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE); - - return TRUE; -} - -/* - * nm_device_check_ip_failed - * - * Progress the device to appropriate state if both IPv4 and IPv6 failed - */ -static void -nm_device_check_ip_failed (NMDevice *self, gboolean may_fail) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMDeviceState state; - - if ( priv->ip4_state != IP_FAIL - || priv->ip6_state != IP_FAIL) - return; - - if (nm_device_uses_assumed_connection (self)) { - /* We have assumed configuration, but couldn't - * redo it. No problem, move to check state. */ - priv->ip4_state = priv->ip6_state = IP_DONE; - state = NM_DEVICE_STATE_IP_CHECK; - } else if ( may_fail - && get_ip_config_may_fail (self, AF_INET) - && get_ip_config_may_fail (self, AF_INET6)) { - /* Couldn't start either IPv6 and IPv4 autoconfiguration, - * but both are allowed to fail. */ - state = NM_DEVICE_STATE_SECONDARIES; - } else { - /* Autoconfiguration attempted without success. */ - state = NM_DEVICE_STATE_FAILED; - } + } else if (ret == NM_ACT_STAGE_RETURN_WAIT) { + /* Wait for something to try IP config again */ + priv->ip6_state = IP_WAIT; + } else + g_assert (ret == NM_ACT_STAGE_RETURN_POSTPONE); - nm_device_state_changed (self, - state, - NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE); + return TRUE; } /* - * nm_device_activate_stage3_ip_config_start + * activate_stage3_ip_config_start * * Begin automatic/manual IP configuration * */ -static gboolean -nm_device_activate_stage3_ip_config_start (gpointer user_data) +static void +activate_stage3_ip_config_start (NMDevice *self) { - NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActiveConnection *master; NMDevice *master_device; - /* Clear the activation source ID now that this stage has run */ - activation_source_clear (self, FALSE, 0); - priv->ip4_state = priv->ip6_state = IP_WAIT; - _LOGD (LOGD_DEVICE, "Activation: Stage 3 of 5 (IP Configure Start) started..."); nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_NONE); /* Device should be up before we can do anything with it */ @@ -5393,50 +6100,75 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data) master_device = nm_active_connection_get_device (master); if (priv->ip4_state == IP_WAIT && priv->ip6_state == IP_WAIT) { _LOGI (LOGD_DEVICE, "Activation: connection '%s' waiting on master '%s'", - nm_connection_get_id (nm_device_get_connection (self)), + nm_connection_get_id (nm_device_get_applied_connection (self)), master_device ? nm_device_get_iface (master_device) : "(unknown)"); } - goto out; + return; } /* IPv4 */ if ( nm_device_activate_ip4_state_in_wait (self) && !nm_device_activate_stage3_ip4_start (self)) - goto out; + return; /* IPv6 */ if ( nm_device_activate_ip6_state_in_wait (self) && !nm_device_activate_stage3_ip6_start (self)) - goto out; + return; nm_device_check_ip_failed (self, TRUE); - -out: - _LOGD (LOGD_DEVICE, "Activation: Stage 3 of 5 (IP Configure Start) complete."); - return FALSE; } +static gboolean +fw_change_zone_handle (NMDevice *self, + NMFirewallManagerCallId call_id, + GError *error) +{ + NMDevicePrivate *priv; + + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + + priv = NM_DEVICE_GET_PRIVATE (self); + + g_return_val_if_fail (priv->fw_call == call_id, FALSE); + priv->fw_call = NULL; + + return !nm_utils_error_is_cancelled (error, FALSE); +} static void -fw_change_zone_cb (GError *error, gpointer user_data) +fw_change_zone_cb_stage2 (NMFirewallManager *firewall_manager, + NMFirewallManagerCallId call_id, + GError *error, + gpointer user_data) { - NMDevice *self; + NMDevice *self = user_data; NMDevicePrivate *priv; - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + if (!fw_change_zone_handle (self, call_id, error)) return; - self = NM_DEVICE (user_data); + /* FIXME: fail the device on error? */ + priv = NM_DEVICE_GET_PRIVATE (self); + priv->fw_ready = TRUE; - priv->fw_call = NULL; + nm_device_activate_schedule_stage3_ip_config_start (self); +} - if (error) { - /* FIXME: fail the device activation? */ - } +static void +fw_change_zone_cb_ip_check (NMFirewallManager *firewall_manager, + NMFirewallManagerCallId call_id, + GError *error, + gpointer user_data) +{ + NMDevice *self = user_data; + + if (!fw_change_zone_handle (self, call_id, error)) + return; - activation_source_schedule (self, nm_device_activate_stage3_ip_config_start, 0); - _LOGD (LOGD_DEVICE, "Activation: Stage 3 of 5 (IP Configure Start) scheduled."); + /* FIXME: fail the device on error? */ + nm_device_start_ip_check (self); } /* @@ -5457,29 +6189,31 @@ nm_device_activate_schedule_stage3_ip_config_start (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); g_return_if_fail (priv->act_request); - g_return_if_fail (!priv->fw_call); - /* Add the interface to the specified firewall zone */ - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); g_assert (connection); s_con = nm_connection_get_setting_connection (connection); - zone = nm_setting_connection_get_zone (s_con); - - if (nm_device_uses_assumed_connection (self)) { - _LOGD (LOGD_DEVICE, "Activation: skip setting firewall zone '%s' for assumed device", zone ? zone : "default"); - activation_source_schedule (self, nm_device_activate_stage3_ip_config_start, 0); - _LOGD (LOGD_DEVICE, "Activation: Stage 3 of 5 (IP Configure Start) scheduled."); - return; + if (!priv->fw_ready) { + if (nm_device_uses_assumed_connection (self)) + priv->fw_ready = TRUE; + else { + if (!priv->fw_call) { + zone = nm_setting_connection_get_zone (s_con); + + _LOGD (LOGD_DEVICE, "Activation: setting firewall zone '%s'", zone ? zone : "default"); + priv->fw_call = nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (), + nm_device_get_ip_iface (self), + zone, + FALSE, + fw_change_zone_cb_stage2, + self); + } + return; + } } - _LOGD (LOGD_DEVICE, "Activation: setting firewall zone '%s'", zone ? zone : "default"); - priv->fw_call = nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (), - nm_device_get_ip_iface (self), - zone, - FALSE, - fw_change_zone_cb, - self); + activation_source_schedule (self, activate_stage3_ip_config_start, AF_INET); } static NMActStageReturn @@ -5499,35 +6233,25 @@ act_stage4_ip4_config_timeout (NMDevice *self, NMDeviceStateReason *reason) * Time out on retrieving the IPv4 config. * */ -static gboolean -nm_device_activate_ip4_config_timeout (gpointer user_data) +static void +activate_stage4_ip4_config_timeout (NMDevice *self) { - NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; - /* Clear the activation source ID now that this stage has run */ - activation_source_clear (self, FALSE, AF_INET); - - _LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 4 of 5 (IPv4 Configure Timeout) started..."); - ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip4_config_timeout (self, &reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) - goto out; + return; else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); - goto out; + return; } - g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); + g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); priv->ip4_state = IP_FAIL; nm_device_check_ip_failed (self, FALSE); - -out: - _LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 4 of 5 (IPv4 Configure Timeout) complete."); - return FALSE; } @@ -5547,9 +6271,7 @@ nm_device_activate_schedule_ip4_config_timeout (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); g_return_if_fail (priv->act_request); - activation_source_schedule (self, nm_device_activate_ip4_config_timeout, AF_INET); - - _LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 4 of 5 (IPv4 Configure Timeout) scheduled..."); + activation_source_schedule (self, activate_stage4_ip4_config_timeout, AF_INET); } @@ -5566,40 +6288,30 @@ act_stage4_ip6_config_timeout (NMDevice *self, NMDeviceStateReason *reason) /* - * nm_device_activate_ip6_config_timeout + * activate_stage4_ip6_config_timeout * * Time out on retrieving the IPv6 config. * */ -static gboolean -nm_device_activate_ip6_config_timeout (gpointer user_data) +static void +activate_stage4_ip6_config_timeout (NMDevice *self) { - NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; - /* Clear the activation source ID now that this stage has run */ - activation_source_clear (self, FALSE, AF_INET6); - - _LOGD (LOGD_DEVICE | LOGD_IP6, "Activation: Stage 4 of 5 (IPv6 Configure Timeout) started..."); - ret = NM_DEVICE_GET_CLASS (self)->act_stage4_ip6_config_timeout (self, &reason); if (ret == NM_ACT_STAGE_RETURN_POSTPONE) - goto out; - else if (ret == NM_ACT_STAGE_RETURN_FAILURE) { + return; + if (ret == NM_ACT_STAGE_RETURN_FAILURE) { nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); - goto out; + return; } g_assert (ret == NM_ACT_STAGE_RETURN_SUCCESS); priv->ip6_state = IP_FAIL; nm_device_check_ip_failed (self, FALSE); - -out: - _LOGD (LOGD_DEVICE | LOGD_IP6, "Activation: Stage 4 of 5 (IPv6 Configure Timeout) complete."); - return FALSE; } @@ -5619,9 +6331,7 @@ nm_device_activate_schedule_ip6_config_timeout (NMDevice *self) priv = NM_DEVICE_GET_PRIVATE (self); g_return_if_fail (priv->act_request); - activation_source_schedule (self, nm_device_activate_ip6_config_timeout, AF_INET6); - - _LOGD (LOGD_DEVICE | LOGD_IP6, "Activation: Stage 4 of 5 (IPv6 Configure Timeout) scheduled..."); + activation_source_schedule (self, activate_stage4_ip6_config_timeout, AF_INET6); } static gboolean @@ -5721,7 +6431,7 @@ start_sharing (NMDevice *self, NMIP4Config *config) return FALSE; } - priv->dnsmasq_state_id = g_signal_connect (priv->dnsmasq_manager, "state-changed", + priv->dnsmasq_state_id = g_signal_connect (priv->dnsmasq_manager, NM_DNS_MASQ_MANAGER_STATE_CHANGED, G_CALLBACK (dnsmasq_state_changed_cb), self); return TRUE; @@ -5738,7 +6448,7 @@ send_arps (NMDevice *self, const char *mode_arg) NMIPAddress *addr; GError *error = NULL; - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); if (!connection) return; s_ip4 = nm_connection_get_setting_ip4_config (connection); @@ -5776,10 +6486,14 @@ send_arps (NMDevice *self, const char *mode_arg) } static gboolean -arp_announce_round2 (gpointer self) +arp_announce_round2 (gpointer user_data) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevice *self = user_data; + NMDevicePrivate *priv; + g_return_val_if_fail (NM_IS_DEVICE (self), G_SOURCE_REMOVE); + + priv = NM_DEVICE_GET_PRIVATE (self); priv->arp_round2_id = 0; if ( priv->state >= NM_DEVICE_STATE_IP_CONFIG @@ -5794,10 +6508,7 @@ arp_cleanup (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->arp_round2_id) { - g_source_remove (priv->arp_round2_id); - priv->arp_round2_id = 0; - } + nm_clear_g_source (&priv->arp_round2_id); } static void @@ -5813,7 +6524,7 @@ arp_announce (NMDevice *self) /* We only care about manually-configured addresses; DHCP- and autoip-configured * ones should already have been seen on the network at this point. */ - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); if (!connection) return; s_ip4 = nm_connection_get_setting_ip4_config (connection); @@ -5827,10 +6538,9 @@ arp_announce (NMDevice *self) priv->arp_round2_id = g_timeout_add_seconds (2, arp_announce_round2, self); } -static gboolean -nm_device_activate_ip4_config_commit (gpointer user_data) +static void +activate_stage5_ip4_config_commit (NMDevice *self) { - NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActRequest *req; const char *method; @@ -5838,14 +6548,9 @@ nm_device_activate_ip4_config_commit (gpointer user_data) NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; int ip_ifindex; - /* Clear the activation source ID now that this stage has run */ - activation_source_clear (self, FALSE, AF_INET); - - _LOGD (LOGD_DEVICE, "Activation: Stage 5 of 5 (IPv4 Commit) started..."); - req = nm_device_get_act_request (self); g_assert (req); - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); g_assert (connection); /* Interface must be IFF_UP before IP config can be applied */ @@ -5860,7 +6565,7 @@ nm_device_activate_ip4_config_commit (gpointer user_data) if (!ip4_config_merge_and_apply (self, NULL, TRUE, &reason)) { _LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 5 of 5 (IPv4 Commit) failed"); nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); - goto out; + return; } /* Start IPv4 sharing if we need it */ @@ -5870,7 +6575,7 @@ nm_device_activate_ip4_config_commit (gpointer user_data) if (!start_sharing (self, priv->ip4_config)) { _LOGW (LOGD_SHARING, "Activation: Stage 5 of 5 (IPv4 Commit) start sharing failed."); nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SHARED_START_FAILED); - goto out; + return; } } @@ -5882,7 +6587,8 @@ nm_device_activate_ip4_config_commit (gpointer user_data) && (nm_device_get_state (self) > NM_DEVICE_STATE_IP_CONFIG)) { /* Notify dispatcher scripts of new DHCP4 config */ nm_dispatcher_call (DISPATCHER_ACTION_DHCP4_CHANGE, - nm_device_get_connection (self), + nm_device_get_settings_connection (self), + nm_device_get_applied_connection (self), self, NULL, NULL, @@ -5898,15 +6604,10 @@ nm_device_activate_ip4_config_commit (gpointer user_data) if (nm_device_get_state (self) == NM_DEVICE_STATE_IP_CONFIG) nm_device_state_changed (self, NM_DEVICE_STATE_IP_CHECK, NM_DEVICE_STATE_REASON_NONE); - -out: - _LOGD (LOGD_DEVICE, "Activation: Stage 5 of 5 (IPv4 Commit) complete."); - - return FALSE; } static void -nm_device_queued_ip_config_change_clear (NMDevice *self) +queued_ip4_config_change_clear (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -5915,6 +6616,13 @@ nm_device_queued_ip_config_change_clear (NMDevice *self) g_source_remove (priv->queued_ip4_config_id); priv->queued_ip4_config_id = 0; } +} + +static void +queued_ip6_config_change_clear (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + if (priv->queued_ip6_config_id) { _LOGD (LOGD_DEVICE, "clearing queued IP6 config change"); g_source_remove (priv->queued_ip6_config_id); @@ -5934,10 +6642,8 @@ nm_device_activate_schedule_ip4_config_result (NMDevice *self, NMIP4Config *conf if (config) priv->dev_ip4_config = g_object_ref (config); - nm_device_queued_ip_config_change_clear (self); - activation_source_schedule (self, nm_device_activate_ip4_config_commit, AF_INET); - - _LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 5 of 5 (IPv4 Configure Commit) scheduled..."); + queued_ip4_config_change_clear (self); + activation_source_schedule (self, activate_stage5_ip4_config_commit, AF_INET); } gboolean @@ -5954,24 +6660,18 @@ nm_device_activate_ip4_state_in_wait (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->ip4_state == IP_WAIT; } -static gboolean -nm_device_activate_ip6_config_commit (gpointer user_data) +static void +activate_stage5_ip6_config_commit (NMDevice *self) { - NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMActRequest *req; NMConnection *connection; NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE; int ip_ifindex; - /* Clear the activation source ID now that this stage has run */ - activation_source_clear (self, FALSE, AF_INET6); - - _LOGD (LOGD_DEVICE, "Activation: Stage 5 of 5 (IPv6 Commit) started..."); - req = nm_device_get_act_request (self); g_assert (req); - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); g_assert (connection); /* Interface must be IFF_UP before IP config can be applied */ @@ -5983,19 +6683,23 @@ nm_device_activate_ip6_config_commit (gpointer user_data) } if (ip6_config_merge_and_apply (self, TRUE, &reason)) { - /* If IPv6 wasn't the first IP to complete, and DHCP was used, - * then ensure dispatcher scripts get the DHCP lease information. - */ - if ( priv->dhcp6_client - && nm_device_activate_ip6_state_in_conf (self) - && (nm_device_get_state (self) > NM_DEVICE_STATE_IP_CONFIG)) { - /* Notify dispatcher scripts of new DHCP6 config */ - nm_dispatcher_call (DISPATCHER_ACTION_DHCP6_CHANGE, - nm_device_get_connection (self), - self, - NULL, - NULL, - NULL); + if ( priv->dhcp6_mode != NM_RDISC_DHCP_LEVEL_NONE + && priv->ip6_state == IP_CONF) { + if (priv->dhcp6_ip6_config) { + /* If IPv6 wasn't the first IP to complete, and DHCP was used, + * then ensure dispatcher scripts get the DHCP lease information. + */ + nm_dispatcher_call (DISPATCHER_ACTION_DHCP6_CHANGE, + nm_device_get_settings_connection (self), + nm_device_get_applied_connection (self), + self, + NULL, + NULL, + NULL); + } else { + /* still waiting for first dhcp6 lease. */ + return; + } } /* Enter the IP_CHECK state if this is the first method to complete */ @@ -6010,10 +6714,6 @@ nm_device_activate_ip6_config_commit (gpointer user_data) _LOGW (LOGD_DEVICE | LOGD_IP6, "Activation: Stage 5 of 5 (IPv6 Commit) failed"); nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); } - - _LOGD (LOGD_DEVICE, "Activation: Stage 5 of 5 (IPv6 Commit) complete."); - - return FALSE; } void @@ -6029,9 +6729,7 @@ nm_device_activate_schedule_ip6_config_result (NMDevice *self) if (priv->ip6_state == IP_FAIL) priv->ip6_state = IP_CONF; - activation_source_schedule (self, nm_device_activate_ip6_config_commit, AF_INET6); - - _LOGD (LOGD_DEVICE | LOGD_IP6, "Activation: Stage 5 of 5 (IPv6 Commit) scheduled..."); + activation_source_schedule (self, activate_stage5_ip6_config_commit, AF_INET6); } gboolean @@ -6073,10 +6771,7 @@ dnsmasq_cleanup (NMDevice *self) if (!priv->dnsmasq_manager) return; - if (priv->dnsmasq_state_id) { - g_signal_handler_disconnect (priv->dnsmasq_manager, priv->dnsmasq_state_id); - priv->dnsmasq_state_id = 0; - } + nm_clear_g_signal_handler (priv->dnsmasq_manager, &priv->dnsmasq_state_id); nm_dnsmasq_manager_stop (priv->dnsmasq_manager); g_object_unref (priv->dnsmasq_manager); @@ -6108,14 +6803,6 @@ nm_device_get_is_nm_owned (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->is_nm_owned; } -void -nm_device_set_nm_owned (NMDevice *self) -{ - g_return_if_fail (NM_IS_DEVICE (self)); - - NM_DEVICE_GET_PRIVATE (self)->is_nm_owned = TRUE; -} - /* * delete_on_deactivate_link_delete * @@ -6129,16 +6816,21 @@ delete_on_deactivate_link_delete (gpointer user_data) DeleteOnDeactivateData *data = user_data; NMDevice *self = data->device; + _LOGD (LOGD_DEVICE, "delete_on_deactivate: cleanup and delete virtual link #%d (id=%u)", + data->ifindex, data->idle_add_id); + if (data->device) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (data->device); + gs_free_error GError *error = NULL; g_object_remove_weak_pointer (G_OBJECT (data->device), (void **) &data->device); priv->delete_on_deactivate_data = NULL; - } - _LOGD (LOGD_DEVICE, "delete_on_deactivate: cleanup and delete virtual link #%d (id=%u)", - data->ifindex, data->idle_add_id); - nm_platform_link_delete (NM_PLATFORM_GET, data->ifindex); + if (!nm_device_unrealize (data->device, TRUE, &error)) + _LOGD (LOGD_DEVICE, "delete_on_deactivate: unrealizing %d failed (%s)", data->ifindex, error->message); + } else + nm_platform_link_delete (NM_PLATFORM_GET, data->ifindex); + g_free (data); return FALSE; } @@ -6173,7 +6865,7 @@ delete_on_deactivate_check_and_schedule (NMDevice *self, int ifindex) return; if (priv->queued_act_request) return; - if (!nm_device_is_software (self)) + if (!nm_device_is_software (self) || !nm_device_is_real (self)) return; if (nm_device_get_state (self) == NM_DEVICE_STATE_UNMANAGED) return; @@ -6192,9 +6884,331 @@ delete_on_deactivate_check_and_schedule (NMDevice *self, int ifindex) ifindex, data->idle_add_id); } +static void +_cleanup_ip4_pre (NMDevice *self, CleanupType cleanup_type) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + priv->ip4_state = IP_NONE; + queued_ip4_config_change_clear (self); + + dhcp4_cleanup (self, cleanup_type, FALSE); + arp_cleanup (self); + dnsmasq_cleanup (self); + ipv4ll_cleanup (self); +} + +static void +_cleanup_ip6_pre (NMDevice *self, CleanupType cleanup_type) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + priv->ip6_state = IP_NONE; + queued_ip6_config_change_clear (self); + + dhcp6_cleanup (self, cleanup_type, FALSE); + linklocal6_cleanup (self); + addrconf6_cleanup (self); +} + +G_GNUC_NULL_TERMINATED +static gboolean +_hash_check_invalid_keys (GHashTable *hash, const char *setting_name, GError **error, ...) +{ + va_list ap; + const char *key; + guint found_keys = 0; + +#if NM_MORE_ASSERTS > 10 + /* Assert that the keys are unique. */ + { + gs_unref_hashtable GHashTable *check_dups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); + + va_start (ap, error); + while ((key = va_arg (ap, const char *))) { + if (!g_hash_table_add (check_dups, (char *) key)) + nm_assert (FALSE); + } + va_end (ap); + nm_assert (g_hash_table_size (check_dups) > 0); + } +#endif + + if (!hash || g_hash_table_size (hash) == 0) + return TRUE; + + va_start (ap, error); + while ((key = va_arg (ap, const char *))) { + if (g_hash_table_contains (hash, key)) + found_keys++; + } + va_end (ap); + + if (found_keys != g_hash_table_size (hash)) { + GHashTableIter iter; + const char *k = NULL; + const char *first_invalid_key = NULL; + + if (!error) + return FALSE; + + g_hash_table_iter_init (&iter, hash); + while (g_hash_table_iter_next (&iter, (gpointer *) &k, NULL)) { + va_start (ap, error); + while ((key = va_arg (ap, const char *))) { + if (!strcmp (key, k)) { + first_invalid_key = k; + break; + } + } + va_end (ap); + if (first_invalid_key) + break; + } + g_set_error (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + "Can't reapply changes to '%s%s%s' setting", + setting_name ? : "", + setting_name ? "." : "", + first_invalid_key ? : ""); + g_return_val_if_fail (first_invalid_key, FALSE); + return FALSE; + } + + return TRUE; +} + +void +nm_device_reactivate_ip4_config (NMDevice *self, + NMSettingIPConfig *s_ip4_old, + NMSettingIPConfig *s_ip4_new) +{ + NMDevicePrivate *priv; + + g_return_if_fail (NM_IS_DEVICE (self)); + priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->ip4_state != IP_NONE) { + g_clear_object (&priv->con_ip4_config); + priv->con_ip4_config = nm_ip4_config_new (nm_device_get_ip_ifindex (self)); + nm_ip4_config_merge_setting (priv->con_ip4_config, + s_ip4_new, + nm_device_get_ip4_route_metric (self)); + + if (strcmp (nm_setting_ip_config_get_method (s_ip4_new), + nm_setting_ip_config_get_method (s_ip4_old))) { + _cleanup_ip4_pre (self, CLEANUP_TYPE_DECONFIGURE); + priv->ip4_state = IP_WAIT; + if (!nm_device_activate_stage3_ip4_start (self)) + _LOGW (LOGD_IP4, "Failed to apply IPv4 configuration"); + } else + ip4_config_merge_and_apply (self, NULL, TRUE, NULL); + } +} + +void +nm_device_reactivate_ip6_config (NMDevice *self, + NMSettingIPConfig *s_ip6_old, + NMSettingIPConfig *s_ip6_new) +{ + NMDevicePrivate *priv; + + g_return_if_fail (NM_IS_DEVICE (self)); + priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->ip6_state != IP_NONE) { + g_clear_object (&priv->con_ip6_config); + priv->con_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self)); + nm_ip6_config_merge_setting (priv->con_ip6_config, + s_ip6_new, + nm_device_get_ip6_route_metric (self)); + + if (strcmp (nm_setting_ip_config_get_method (s_ip6_new), + nm_setting_ip_config_get_method (s_ip6_old))) { + _cleanup_ip6_pre (self, CLEANUP_TYPE_DECONFIGURE); + priv->ip6_state = IP_WAIT; + if (!nm_device_activate_stage3_ip6_start (self)) + _LOGW (LOGD_IP6, "Failed to apply IPv6 configuration"); + } else + ip6_config_merge_and_apply (self, TRUE, NULL); + } +} + + +/* reapply_connection: + * @connection: the new connection settings to be applied or %NULL to reapply + * the current settings connection + * @error: the error if %FALSE is returned + * + * Change configuration of an already configured device if possible. + * Updates the device's applied connection upon success. + * + * Return: %FALSE if the new configuration can not be reapplied. + */ +static gboolean +reapply_connection (NMDevice *self, + NMConnection *connection, + GError **error) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMConnection *applied = nm_device_get_applied_connection (self); + gs_unref_object NMConnection *applied_clone = NULL; + gs_unref_hashtable GHashTable *diffs = NULL; + NMConnection *con_old, *con_new; + NMSettingIPConfig *s_ip4_old, *s_ip4_new; + NMSettingIPConfig *s_ip6_old, *s_ip6_new; + + if (priv->state != NM_DEVICE_STATE_ACTIVATED) { + g_set_error_literal (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ACTIVE, + "Device is not activated"); + return FALSE; + } + + nm_connection_diff (connection, + applied, + NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP | + NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS, + &diffs); + + /************************************************************************** + * check for unsupported changes and reject to reapply + *************************************************************************/ + if (!_hash_check_invalid_keys (diffs, NULL, error, + NM_SETTING_IP4_CONFIG_SETTING_NAME, + NM_SETTING_IP6_CONFIG_SETTING_NAME, + NM_SETTING_CONNECTION_SETTING_NAME, + NULL)) + return FALSE; + + if (!_hash_check_invalid_keys (diffs ? g_hash_table_lookup (diffs, NM_SETTING_CONNECTION_SETTING_NAME) : NULL, + NM_SETTING_CONNECTION_SETTING_NAME, + error, + NM_SETTING_CONNECTION_ZONE, + NM_SETTING_CONNECTION_METERED, + NULL)) + return FALSE; + + _LOGD (LOGD_DEVICE, "reapply"); + + /************************************************************************** + * Update applied connection + *************************************************************************/ + + if (diffs) { + con_old = applied_clone = nm_simple_connection_new_clone (applied); + con_new = applied; + nm_connection_replace_settings_from_connection (applied, connection); + } else + con_old = con_new = applied; + + s_ip4_new = nm_connection_get_setting_ip4_config (con_new); + s_ip4_old = nm_connection_get_setting_ip4_config (con_old); + s_ip6_new = nm_connection_get_setting_ip6_config (con_new); + s_ip6_old = nm_connection_get_setting_ip6_config (con_old); + + /************************************************************************** + * Reapply changes + *************************************************************************/ + + nm_device_update_firewall_zone (self); + nm_device_update_metered (self); + + nm_device_reactivate_ip4_config (self, s_ip4_old, s_ip4_new); + nm_device_reactivate_ip6_config (self, s_ip6_old, s_ip6_new); + + return TRUE; +} + +static void +reapply_cb (NMDevice *self, + GDBusMethodInvocation *context, + NMAuthSubject *subject, + GError *error, + gpointer user_data) +{ + gs_unref_object NMConnection *connection = NM_CONNECTION (user_data); + GError *local = NULL; + + if (error) { + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, subject, error->message); + g_dbus_method_invocation_return_gerror (context, error); + return; + } + + if (!reapply_connection (self, + connection ? : (NMConnection *) nm_device_get_settings_connection (self), + &local)) { + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, subject, local->message); + g_dbus_method_invocation_take_error (context, local); + local = NULL; + } else { + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, TRUE, subject, NULL); + g_dbus_method_invocation_return_value (context, NULL); + } +} + +static void +impl_device_reapply (NMDevice *self, + GDBusMethodInvocation *context, + GVariant *settings, + guint flags) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMSettingsConnection *settings_connection; + NMConnection *connection = NULL; + GError *error = NULL; + + /* No flags supported as of now. */ + if (flags != 0) { + error = g_error_new_literal (NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ACTIVE, + "Invalid flags specified"); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, context, error->message); + g_dbus_method_invocation_take_error (context, error); + return; + } + + if (priv->state != NM_DEVICE_STATE_ACTIVATED) { + error = g_error_new_literal (NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ACTIVE, + "Device is not activated"); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, context, error->message); + g_dbus_method_invocation_take_error (context, error); + return; + } + + settings_connection = nm_device_get_settings_connection (self); + g_return_if_fail (settings_connection); + + if (settings && g_variant_n_children (settings)) { + /* New settings specified inline. */ + connection = nm_simple_connection_new_from_dbus (settings, &error); + if (!connection) { + g_prefix_error (&error, "The settings specified are invalid: "); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, context, error->message); + g_dbus_method_invocation_take_error (context, error); + return; + } + nm_connection_clear_secrets (connection); + } + + /* Ask the manager to authenticate this request for us */ + g_signal_emit (self, signals[AUTH_REQUEST], 0, + context, + nm_device_get_applied_connection (self), + NM_AUTH_PERMISSION_NETWORK_CONTROL, + TRUE, + reapply_cb, + connection); +} + static void disconnect_cb (NMDevice *self, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, + NMAuthSubject *subject, GError *error, gpointer user_data) { @@ -6202,7 +7216,8 @@ disconnect_cb (NMDevice *self, GError *local = NULL; if (error) { - dbus_g_method_return_error (context, error); + g_dbus_method_invocation_return_gerror (context, error); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, FALSE, subject, error->message); return; } @@ -6211,15 +7226,16 @@ disconnect_cb (NMDevice *self, local = g_error_new_literal (NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ACTIVE, "Device is not active"); - dbus_g_method_return_error (context, local); - g_error_free (local); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, FALSE, subject, local->message); + g_dbus_method_invocation_take_error (context, local); } else { nm_device_set_autoconnect (self, FALSE); nm_device_state_changed (self, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_USER_REQUESTED); - dbus_g_method_return (context); + g_dbus_method_invocation_return_value (context, NULL); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DISCONNECT, self, TRUE, subject, NULL); } } @@ -6233,7 +7249,7 @@ _clear_queued_act_request (NMDevicePrivate *priv) } static void -impl_device_disconnect (NMDevice *self, DBusGMethodInvocation *context) +impl_device_disconnect (NMDevice *self, GDBusMethodInvocation *context) { NMConnection *connection; GError *error = NULL; @@ -6242,12 +7258,11 @@ impl_device_disconnect (NMDevice *self, DBusGMethodInvocation *context) error = g_error_new_literal (NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_ACTIVE, "This device is not active"); - dbus_g_method_return_error (context, error); - g_error_free (error); + g_dbus_method_invocation_take_error (context, error); return; } - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); g_assert (connection); /* Ask the manager to authenticate this request for us */ @@ -6262,31 +7277,37 @@ impl_device_disconnect (NMDevice *self, DBusGMethodInvocation *context) static void delete_cb (NMDevice *self, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, + NMAuthSubject *subject, GError *error, gpointer user_data) { + GError *local = NULL; + if (error) { - dbus_g_method_return_error (context, error); + g_dbus_method_invocation_return_gerror (context, error); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DELETE, self, FALSE, subject, error->message); return; } /* Authorized */ - nm_platform_link_delete (NM_PLATFORM_GET, nm_device_get_ifindex (self)); - dbus_g_method_return (context); + nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_DELETE, self, TRUE, subject, NULL); + if (nm_device_unrealize (self, TRUE, &local)) + g_dbus_method_invocation_return_value (context, NULL); + else + g_dbus_method_invocation_take_error (context, local); } static void -impl_device_delete (NMDevice *self, DBusGMethodInvocation *context) +impl_device_delete (NMDevice *self, GDBusMethodInvocation *context) { GError *error = NULL; - if (!nm_device_is_software (self)) { + if (!nm_device_is_software (self) || !nm_device_is_real (self)) { error = g_error_new_literal (NM_DEVICE_ERROR, NM_DEVICE_ERROR_NOT_SOFTWARE, - "This device is not a software device"); - dbus_g_method_return_error (context, error); - g_error_free (error); + "This device is not a software device or is not realized"); + g_dbus_method_invocation_take_error (context, error); return; } @@ -6317,7 +7338,7 @@ _device_activate (NMDevice *self, NMActRequest *req) priv = NM_DEVICE_GET_PRIVATE (self); - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); g_assert (connection); _LOGI (LOGD_DEVICE, "Activation: starting connection '%s' (%s)", @@ -6378,7 +7399,7 @@ _carrier_wait_check_act_request_must_queue (NMDevice *self, NMActRequest *req) if (priv->carrier_wait_id == 0) return FALSE; - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); if (!connection_requires_carrier (connection)) return FALSE; @@ -6408,19 +7429,19 @@ _carrier_wait_check_act_request_must_queue (NMDevice *self, NMActRequest *req) } void -nm_device_steal_connection (NMDevice *self, NMConnection *connection) +nm_device_steal_connection (NMDevice *self, NMSettingsConnection *connection) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); _LOGW (LOGD_DEVICE, "disconnecting connection '%s' for new activation request.", - nm_connection_get_id (connection)); + nm_settings_connection_get_id (connection)); if ( priv->queued_act_request - && connection == nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (priv->queued_act_request))) + && connection == nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (priv->queued_act_request))) _clear_queued_act_request (priv); if ( priv->act_request - && connection == nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (priv->act_request)) + && connection == nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (priv->act_request)) && priv->state < NM_DEVICE_STATE_DEACTIVATING) nm_device_state_changed (self, NM_DEVICE_STATE_DEACTIVATING, @@ -6481,7 +7502,7 @@ nm_device_is_activating (NMDevice *self) * handler is actually run. If there's an activation handler scheduled * we're activating anyway. */ - return priv->act_source_id ? TRUE : FALSE; + return priv->act_handle4.id ? TRUE : FALSE; } /* IP Configuration stuff */ @@ -6516,13 +7537,19 @@ nm_device_set_ip4_config (NMDevice *self, gboolean has_changes = FALSE; gboolean success = TRUE; NMDeviceStateReason reason_local = NM_DEVICE_STATE_REASON_NONE; - int ip_ifindex; + int ip_ifindex, config_ifindex; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); priv = NM_DEVICE_GET_PRIVATE (self); ip_ifindex = nm_device_get_ip_ifindex (self); + if (new_config) { + config_ifindex = nm_ip4_config_get_ifindex (new_config); + if (config_ifindex > 0) + g_return_val_if_fail (ip_ifindex == config_ifindex, FALSE); + } + old_config = priv->ip4_config; /* Always commit to nm-platform to update lifetimes */ @@ -6548,25 +7575,23 @@ nm_device_set_ip4_config (NMDevice *self, nm_ip4_config_replace (old_config, new_config, &has_changes); if (has_changes) { _LOGD (LOGD_IP4, "update IP4Config instance (%s)", - nm_ip4_config_get_dbus_path (old_config)); + nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config))); } } else { has_changes = TRUE; priv->ip4_config = g_object_ref (new_config); - if (success && !nm_ip4_config_get_dbus_path (new_config)) { - /* Export over D-Bus */ - nm_ip4_config_export (new_config); - } + if (success && !nm_exported_object_is_exported (NM_EXPORTED_OBJECT (new_config))) + nm_exported_object_export (NM_EXPORTED_OBJECT (new_config)); _LOGD (LOGD_IP4, "set IP4Config instance (%s)", - nm_ip4_config_get_dbus_path (new_config)); + nm_exported_object_get_path (NM_EXPORTED_OBJECT (new_config))); } } else if (old_config) { has_changes = TRUE; priv->ip4_config = NULL; _LOGD (LOGD_IP4, "clear IP4Config instance (%s)", - nm_ip4_config_get_dbus_path (old_config)); + nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config))); /* Device config is invalid if combined config is invalid */ g_clear_object (&priv->dev_ip4_config); } @@ -6580,17 +7605,26 @@ nm_device_set_ip4_config (NMDevice *self, g_object_notify (G_OBJECT (self), NM_DEVICE_IP4_CONFIG); g_signal_emit (self, signals[IP4_CONFIG_CHANGED], 0, priv->ip4_config, old_config); - if (old_config != priv->ip4_config && old_config) - g_object_unref (old_config); + if (old_config != priv->ip4_config) + nm_exported_object_clear_and_unexport (&old_config); if (nm_device_uses_generated_assumed_connection (self)) { - NMConnection *connection = nm_device_get_connection (self); + NMConnection *connection = nm_device_get_applied_connection (self); + NMConnection *settings_connection = NM_CONNECTION (nm_device_get_settings_connection (self)); NMSetting *s_ip4; g_object_freeze_notify (G_OBJECT (connection)); + g_object_freeze_notify (G_OBJECT (settings_connection)); + + nm_connection_remove_setting (settings_connection, NM_TYPE_SETTING_IP4_CONFIG); + s_ip4 = nm_ip4_config_create_setting (priv->ip4_config); + nm_connection_add_setting (settings_connection, s_ip4); + nm_connection_remove_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); s_ip4 = nm_ip4_config_create_setting (priv->ip4_config); nm_connection_add_setting (connection, s_ip4); + + g_object_thaw_notify (G_OBJECT (settings_connection)); g_object_thaw_notify (G_OBJECT (connection)); } @@ -6603,18 +7637,49 @@ nm_device_set_ip4_config (NMDevice *self, return success; } +static gboolean +_replace_vpn_config_in_list (GSList **plist, GObject *old, GObject *new) +{ + GSList *old_link; + + /* Below, assert that we have an @old instance to replace and that + * @new is not yet tracked. But still, behave correctly in any + * case. */ + + if ( old + && (old_link = g_slist_find (*plist, old))) { + if (old != new) { + if (new) + old_link->data = g_object_ref (new); + else + *plist = g_slist_remove_link (*plist, old_link); + g_object_unref (old); + } + return TRUE; + } + + if (new) { + if (!g_slist_find (*plist, new)) + *plist = g_slist_append (*plist, g_object_ref (new)); + else + g_return_val_if_reached (TRUE); + g_return_val_if_fail (!old, TRUE); + return TRUE; + } + + /* return FALSE if both @old and @new are unset. */ + g_return_val_if_fail (!old, FALSE); + return FALSE; +} + void -nm_device_set_vpn4_config (NMDevice *self, NMIP4Config *config) +nm_device_replace_vpn4_config (NMDevice *self, NMIP4Config *old, NMIP4Config *config) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->vpn4_config == config) + if (!_replace_vpn_config_in_list (&priv->vpn4_configs, (GObject *) old, (GObject *) config)) return; - g_clear_object (&priv->vpn4_config); - if (config) - priv->vpn4_config = g_object_ref (config); - /* NULL to use existing configs */ if (!ip4_config_merge_and_apply (self, NULL, TRUE, NULL)) _LOGW (LOGD_IP4, "failed to set VPN routes for device"); @@ -6649,13 +7714,19 @@ nm_device_set_ip6_config (NMDevice *self, gboolean has_changes = FALSE; gboolean success = TRUE; NMDeviceStateReason reason_local = NM_DEVICE_STATE_REASON_NONE; - int ip_ifindex; + int ip_ifindex, config_ifindex; g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); priv = NM_DEVICE_GET_PRIVATE (self); ip_ifindex = nm_device_get_ip_ifindex (self); + if (new_config) { + config_ifindex = nm_ip6_config_get_ifindex (new_config); + if (config_ifindex > 0) + g_return_val_if_fail (ip_ifindex == config_ifindex, FALSE); + } + old_config = priv->ip6_config; /* Always commit to nm-platform to update lifetimes */ @@ -6675,25 +7746,23 @@ nm_device_set_ip6_config (NMDevice *self, nm_ip6_config_replace (old_config, new_config, &has_changes); if (has_changes) { _LOGD (LOGD_IP6, "update IP6Config instance (%s)", - nm_ip6_config_get_dbus_path (old_config)); + nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config))); } } else { has_changes = TRUE; priv->ip6_config = g_object_ref (new_config); - if (success && !nm_ip6_config_get_dbus_path (new_config)) { - /* Export over D-Bus */ - nm_ip6_config_export (new_config); - } + if (success && !nm_exported_object_is_exported (NM_EXPORTED_OBJECT (new_config))) + nm_exported_object_export (NM_EXPORTED_OBJECT (new_config)); _LOGD (LOGD_IP6, "set IP6Config instance (%s)", - nm_ip6_config_get_dbus_path (new_config)); + nm_exported_object_get_path (NM_EXPORTED_OBJECT (new_config))); } } else if (old_config) { has_changes = TRUE; priv->ip6_config = NULL; _LOGD (LOGD_IP6, "clear IP6Config instance (%s)", - nm_ip6_config_get_dbus_path (old_config)); + nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config))); } nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), self); @@ -6703,17 +7772,26 @@ nm_device_set_ip6_config (NMDevice *self, g_object_notify (G_OBJECT (self), NM_DEVICE_IP6_CONFIG); g_signal_emit (self, signals[IP6_CONFIG_CHANGED], 0, priv->ip6_config, old_config); - if (old_config != priv->ip6_config && old_config) - g_object_unref (old_config); + if (old_config != priv->ip6_config) + nm_exported_object_clear_and_unexport (&old_config); if (nm_device_uses_generated_assumed_connection (self)) { - NMConnection *connection = nm_device_get_connection (self); + NMConnection *connection = nm_device_get_applied_connection (self); + NMConnection *settings_connection = NM_CONNECTION (nm_device_get_settings_connection (self)); NMSetting *s_ip6; g_object_freeze_notify (G_OBJECT (connection)); + g_object_freeze_notify (G_OBJECT (settings_connection)); + + nm_connection_remove_setting (settings_connection, NM_TYPE_SETTING_IP6_CONFIG); + s_ip6 = nm_ip6_config_create_setting (priv->ip6_config); + nm_connection_add_setting (settings_connection, s_ip6); + nm_connection_remove_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); s_ip6 = nm_ip6_config_create_setting (priv->ip6_config); nm_connection_add_setting (connection, s_ip6); + + g_object_thaw_notify (G_OBJECT (settings_connection)); g_object_thaw_notify (G_OBJECT (connection)); } @@ -6727,17 +7805,13 @@ nm_device_set_ip6_config (NMDevice *self, } void -nm_device_set_vpn6_config (NMDevice *self, NMIP6Config *config) +nm_device_replace_vpn6_config (NMDevice *self, NMIP6Config *old, NMIP6Config *config) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->vpn6_config == config) + if (!_replace_vpn_config_in_list (&priv->vpn6_configs, (GObject *) old, (GObject *) config)) return; - g_clear_object (&priv->vpn6_config); - if (config) - priv->vpn6_config = g_object_ref (config); - /* NULL to use existing configs */ if (!ip6_config_merge_and_apply (self, TRUE, NULL)) _LOGW (LOGD_IP6, "failed to set VPN routes for device"); @@ -6821,7 +7895,8 @@ ip_check_pre_up (NMDevice *self) priv->dispatcher.post_state = NM_DEVICE_STATE_SECONDARIES; priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE; if (!nm_dispatcher_call (DISPATCHER_ACTION_PRE_UP, - nm_device_get_connection (self), + nm_device_get_settings_connection (self), + nm_device_get_applied_connection (self), self, dispatcher_complete_proceed_state, self, @@ -6904,7 +7979,7 @@ ip_check_ping_watch_cb (GPid pid, gint status, gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - guint log_domain = priv->gw_ping.log_domain; + NMLogDomain log_domain = priv->gw_ping.log_domain; gboolean success = FALSE; if (!priv->gw_ping.watch) @@ -6951,7 +8026,7 @@ ip_check_ping_timeout_cb (gpointer user_data) static gboolean start_ping (NMDevice *self, - guint log_domain, + NMLogDomain log_domain, const char *binary, const char *address, guint timeout) @@ -6985,7 +8060,7 @@ nm_device_start_ip_check (NMDevice *self) guint timeout = 0; const char *ping_binary = NULL; char buf[INET6_ADDRSTRLEN] = { 0 }; - guint log_domain = LOGD_IP4; + NMLogDomain log_domain = LOGD_IP4; /* Shouldn't be any active ping here, since IP_CHECK happens after the * first IP method completes. Any subsequently completing IP method doesn't @@ -6996,7 +8071,7 @@ nm_device_start_ip_check (NMDevice *self) g_assert (!priv->gw_ping.pid); g_assert (priv->ip4_state == IP_DONE || priv->ip6_state == IP_DONE); - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); g_assert (connection); s_con = nm_connection_get_setting_connection (connection); @@ -7210,12 +8285,33 @@ nm_device_get_firmware_missing (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->firmware_missing; } +void +nm_device_set_nm_plugin_missing (NMDevice *self, gboolean new_missing) +{ + NMDevicePrivate *priv; + + g_return_if_fail (NM_IS_DEVICE (self)); + + priv = NM_DEVICE_GET_PRIVATE (self); + if (priv->nm_plugin_missing != new_missing) { + priv->nm_plugin_missing = new_missing; + g_object_notify (G_OBJECT (self), NM_DEVICE_NM_PLUGIN_MISSING); + } +} + +gboolean +nm_device_get_nm_plugin_missing (NMDevice *self) +{ + return NM_DEVICE_GET_PRIVATE (self)->nm_plugin_missing; +} + static NMIP4Config * find_ip4_lease_config (NMDevice *self, NMConnection *connection, NMIP4Config *ext_ip4_config) { const char *ip_iface = nm_device_get_ip_iface (self); + int ip_ifindex = nm_device_get_ip_ifindex (self); GSList *leases, *liter; NMIP4Config *found = NULL; @@ -7224,6 +8320,7 @@ find_ip4_lease_config (NMDevice *self, leases = nm_dhcp_manager_get_lease_ip_configs (nm_dhcp_manager_get (), ip_iface, + ip_ifindex, nm_connection_get_uuid (connection), FALSE, nm_device_get_ip4_route_metric (self)); @@ -7309,6 +8406,24 @@ capture_lease_config (NMDevice *self, } } +static void +_ip4_config_intersect (gpointer value, gpointer user_data) +{ + NMIP4Config *dst = (NMIP4Config *) value; + NMIP4Config *src = (NMIP4Config *) user_data; + + nm_ip4_config_intersect (dst, src); +} + +static void +_ip4_config_subtract (gpointer value, gpointer user_data) +{ + NMIP4Config *dst = (NMIP4Config *) user_data; + NMIP4Config *src = (NMIP4Config *) value; + + nm_ip4_config_subtract (dst, src); +} + static void update_ip4_config (NMDevice *self, gboolean initial) { @@ -7339,15 +8454,16 @@ update_ip4_config (NMDevice *self, gboolean initial) * kernel routes. */ /* This function was called upon external changes. Remove the configuration - * (adresses,routes) that is no longer present externally from the interal - * config. This way, we don't readd addresses that were manually removed + * (addresses,routes) that is no longer present externally from the internal + * config. This way, we don't re-add addresses that were manually removed * by the user. */ if (priv->con_ip4_config) nm_ip4_config_intersect (priv->con_ip4_config, priv->ext_ip4_config); if (priv->dev_ip4_config) nm_ip4_config_intersect (priv->dev_ip4_config, priv->ext_ip4_config); - if (priv->vpn4_config) - nm_ip4_config_intersect (priv->vpn4_config, priv->ext_ip4_config); + + g_slist_foreach (priv->vpn4_configs, _ip4_config_intersect, priv->ext_ip4_config); + if (priv->wwan_ip4_config) nm_ip4_config_intersect (priv->wwan_ip4_config, priv->ext_ip4_config); @@ -7358,8 +8474,9 @@ update_ip4_config (NMDevice *self, gboolean initial) nm_ip4_config_subtract (priv->ext_ip4_config, priv->con_ip4_config); if (priv->dev_ip4_config) nm_ip4_config_subtract (priv->ext_ip4_config, priv->dev_ip4_config); - if (priv->vpn4_config) - nm_ip4_config_subtract (priv->ext_ip4_config, priv->vpn4_config); + + g_slist_foreach (priv->vpn4_configs, _ip4_config_subtract, priv->ext_ip4_config); + if (priv->wwan_ip4_config) nm_ip4_config_subtract (priv->ext_ip4_config, priv->wwan_ip4_config); @@ -7367,6 +8484,24 @@ update_ip4_config (NMDevice *self, gboolean initial) } } +static void +_ip6_config_intersect (gpointer value, gpointer user_data) +{ + NMIP6Config *dst = (NMIP6Config *) value; + NMIP6Config *src = (NMIP6Config *) user_data; + + nm_ip6_config_intersect (dst, src); +} + +static void +_ip6_config_subtract (gpointer value, gpointer user_data) +{ + NMIP6Config *dst = (NMIP6Config *) user_data; + NMIP6Config *src = (NMIP6Config *) value; + + nm_ip6_config_subtract (dst, src); +} + static void update_ip6_config (NMDevice *self, gboolean initial) { @@ -7393,8 +8528,8 @@ update_ip6_config (NMDevice *self, gboolean initial) have_ip6_address (priv->ext_ip6_config, TRUE); /* This function was called upon external changes. Remove the configuration - * (adresses,routes) that is no longer present externally from the interal - * config. This way, we don't readd addresses that were manually removed + * (addresses,routes) that is no longer present externally from the internal + * config. This way, we don't re-add addresses that were manually removed * by the user. */ if (priv->con_ip6_config) nm_ip6_config_intersect (priv->con_ip6_config, priv->ext_ip6_config); @@ -7404,8 +8539,7 @@ update_ip6_config (NMDevice *self, gboolean initial) nm_ip6_config_intersect (priv->dhcp6_ip6_config, priv->ext_ip6_config); if (priv->wwan_ip6_config) nm_ip6_config_intersect (priv->wwan_ip6_config, priv->ext_ip6_config); - if (priv->vpn6_config) - nm_ip6_config_intersect (priv->vpn6_config, priv->ext_ip6_config); + g_slist_foreach (priv->vpn6_configs, _ip6_config_intersect, priv->ext_ip6_config); /* Remove parts from ext_ip6_config to only contain the information that * was configured externally -- we already have the same configuration from @@ -7418,8 +8552,7 @@ update_ip6_config (NMDevice *self, gboolean initial) nm_ip6_config_subtract (priv->ext_ip6_config, priv->dhcp6_ip6_config); if (priv->wwan_ip6_config) nm_ip6_config_subtract (priv->ext_ip6_config, priv->wwan_ip6_config); - if (priv->vpn6_config) - nm_ip6_config_subtract (priv->ext_ip6_config, priv->vpn6_config); + g_slist_foreach (priv->vpn6_configs, _ip6_config_subtract, priv->ext_ip6_config); ip6_config_merge_and_apply (self, FALSE, NULL); } @@ -7462,6 +8595,8 @@ queued_ip6_config_change (gpointer user_data) { NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + GSList *iter; + gboolean need_ipv6ll = FALSE; /* Wait for any queued state changes */ if (priv->queued_state.id) @@ -7471,13 +8606,38 @@ queued_ip6_config_change (gpointer user_data) g_object_ref (self); update_ip6_config (self, FALSE); - /* If no IPv6 link-local address exists but other addresses do then we - * must add the LL address to remain conformant with RFC 3513 chapter 2.1 - * ("Addressing Model"): "All interfaces are required to have at least - * one link-local unicast address". - */ - if (priv->ip6_config && nm_ip6_config_get_num_addresses (priv->ip6_config)) - check_and_add_ipv6ll_addr (self); + if ( nm_platform_link_get (NM_PLATFORM_GET, priv->ifindex) + && priv->state < NM_DEVICE_STATE_DEACTIVATING) { + /* Handle DAD falures */ + for (iter = priv->dad6_failed_addrs; iter; iter = g_slist_next (iter)) { + NMPlatformIP6Address *addr = iter->data; + + if (addr->source >= NM_IP_CONFIG_SOURCE_USER) + continue; + + _LOGI (LOGD_IP6, "ipv6: duplicate address check failed for the %s address", + nm_platform_ip6_address_to_string (addr, NULL, 0)); + + if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) + need_ipv6ll = TRUE; + else if (priv->rdisc) + nm_rdisc_dad_failed (priv->rdisc, &addr->address); + } + + /* If no IPv6 link-local address exists but other addresses do then we + * must add the LL address to remain conformant with RFC 3513 chapter 2.1 + * ("Addressing Model"): "All interfaces are required to have at least + * one link-local unicast address". + */ + if (priv->ip6_config && nm_ip6_config_get_num_addresses (priv->ip6_config)) + need_ipv6ll = TRUE; + + if (need_ipv6ll) + check_and_add_ipv6ll_addr (self); + } + + g_slist_free_full (priv->dad6_failed_addrs, g_free); + priv->dad6_failed_addrs = NULL; g_object_unref (self); @@ -7490,15 +8650,16 @@ device_ipx_changed (NMPlatform *platform, int ifindex, gpointer platform_object, NMPlatformSignalChangeType change_type, - NMPlatformReason reason, NMDevice *self) { NMDevicePrivate *priv; + NMPlatformIP6Address *addr; if (nm_device_get_ip_ifindex (self) != ifindex) return; priv = NM_DEVICE_GET_PRIVATE (self); + switch (obj_type) { case NMP_OBJECT_TYPE_IP4_ADDRESS: case NMP_OBJECT_TYPE_IP4_ROUTE: @@ -7508,6 +8669,16 @@ device_ipx_changed (NMPlatform *platform, } break; case NMP_OBJECT_TYPE_IP6_ADDRESS: + addr = platform_object; + + if ( priv->state > NM_DEVICE_STATE_DISCONNECTED + && priv->state < NM_DEVICE_STATE_DEACTIVATING + && ( (change_type == NM_PLATFORM_SIGNAL_CHANGED && addr->flags & IFA_F_DADFAILED) + || (change_type == NM_PLATFORM_SIGNAL_REMOVED && addr->flags & IFA_F_TENTATIVE))) { + priv->dad6_failed_addrs = g_slist_append (priv->dad6_failed_addrs, + g_memdup (addr, sizeof (NMPlatformIP6Address))); + } + /* fallthrough */ case NMP_OBJECT_TYPE_IP6_ROUTE: if (!priv->queued_ip6_config_id) { priv->queued_ip6_config_id = g_idle_add (queued_ip6_config_change, self); @@ -7540,23 +8711,24 @@ nm_device_get_managed (NMDevice *self) * default-unmanaged flag (eg, only NM_UNMANAGED_DEFAULT is set) then * the device is managed whenever it's not in the UNMANAGED state. */ - managed = !(priv->unmanaged_flags & ~NM_UNMANAGED_DEFAULT); - if (managed && (priv->unmanaged_flags & NM_UNMANAGED_DEFAULT)) + managed = !NM_FLAGS_ANY (priv->unmanaged_flags, ~NM_UNMANAGED_DEFAULT); + if (managed && NM_FLAGS_HAS (priv->unmanaged_flags, NM_UNMANAGED_DEFAULT)) managed = (priv->state > NM_DEVICE_STATE_UNMANAGED); return managed; } /** - * nm_device_get_unmanaged_flag(): + * nm_device_get_unmanaged_flags(): * @self: the #NMDevice + * @flag: return only the selected flags * - * Returns: %TRUE if the device is unmanaged for @flag. + * Returns: the unmanage flags of the device (filtered with @flag) */ -gboolean -nm_device_get_unmanaged_flag (NMDevice *self, NMUnmanagedFlags flag) +NMUnmanagedFlags +nm_device_get_unmanaged_flags (NMDevice *self, NMUnmanagedFlags flag) { - return NM_FLAGS_ANY (NM_DEVICE_GET_PRIVATE (self)->unmanaged_flags, flag); + return NM_DEVICE_GET_PRIVATE (self)->unmanaged_flags & flag; } /** @@ -7568,14 +8740,42 @@ nm_device_get_unmanaged_flag (NMDevice *self, NMUnmanagedFlags flag) static gboolean nm_device_get_default_unmanaged (NMDevice *self) { - return nm_device_get_unmanaged_flag (self, NM_UNMANAGED_DEFAULT); + return !!nm_device_get_unmanaged_flags (self, NM_UNMANAGED_DEFAULT); +} + +static void +_set_unmanaged_flags (NMDevice *self, + NMUnmanagedFlags flags, + gboolean unmanaged) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (unmanaged) { + if (!NM_FLAGS_ALL (priv->unmanaged_flags, flags)) { + _LOGD (LOGD_DEVICE, "unmanaged: flags set to 0x%0llx (was 0x%0llx, %s 0x%0llx)", + (long long unsigned) (priv->unmanaged_flags | flags), + (long long unsigned) priv->unmanaged_flags, + "set", + (long long unsigned) flags); + priv->unmanaged_flags |= flags; + } + } else { + if (NM_FLAGS_ANY (priv->unmanaged_flags, flags)) { + _LOGD (LOGD_DEVICE, "unmanaged: flags set to 0x%0llx (was 0x%0llx, %s 0x%0llx)", + (long long unsigned) (priv->unmanaged_flags & (~flags)), + (long long unsigned) priv->unmanaged_flags, + "clear", + (long long unsigned) flags); + priv->unmanaged_flags &= ~flags; + } + } } void -nm_device_set_unmanaged (NMDevice *self, - NMUnmanagedFlags flag, - gboolean unmanaged, - NMDeviceStateReason reason) +nm_device_set_unmanaged_flags (NMDevice *self, + NMUnmanagedFlags flag, + gboolean unmanaged, + NMDeviceStateReason reason) { NMDevicePrivate *priv; gboolean was_managed, now_managed; @@ -7586,10 +8786,7 @@ nm_device_set_unmanaged (NMDevice *self, priv = NM_DEVICE_GET_PRIVATE (self); was_managed = nm_device_get_managed (self); - if (unmanaged) - priv->unmanaged_flags |= flag; - else - priv->unmanaged_flags &= ~flag; + _set_unmanaged_flags (self, flag, unmanaged); now_managed = nm_device_get_managed (self); if (was_managed != now_managed) { @@ -7605,34 +8802,41 @@ nm_device_set_unmanaged (NMDevice *self, } void -nm_device_set_unmanaged_quitting (NMDevice *self) +nm_device_set_unmanaged_flags_by_device_spec (NMDevice *self, const GSList *unmanaged_specs) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv; + gboolean unmanaged; - /* It's OK to block here because we're quitting */ - if (nm_device_is_activating (self) || priv->state == NM_DEVICE_STATE_ACTIVATED) - _set_state_full (self, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_NOW_UNMANAGED, TRUE); + g_return_if_fail (NM_IS_DEVICE (self)); + + priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->managed_touched_by_user) + return; - nm_device_set_unmanaged (self, - NM_UNMANAGED_INTERNAL, - TRUE, - NM_DEVICE_STATE_REASON_NOW_UNMANAGED); + unmanaged = nm_device_spec_match_list (self, unmanaged_specs); + nm_device_set_unmanaged_flags (self, + NM_UNMANAGED_USER, + unmanaged, + unmanaged + ? NM_DEVICE_STATE_REASON_NOW_UNMANAGED + : NM_DEVICE_STATE_REASON_NOW_MANAGED); } /** - * nm_device_set_initial_unmanaged_flag(): + * nm_device_set_unmanaged_flags_initial(): * @self: the #NMDevice * @flag: an #NMUnmanagedFlag * @unmanaged: %TRUE or %FALSE to set or clear @flag * - * Like nm_device_set_unmanaged(), but must be set before the device is + * Like nm_device_set_unmanaged_flags(), but must be set before the device is * initialized by nm_device_finish_init(), and does not trigger state changes. * Should only be used when initializing a device. */ void -nm_device_set_initial_unmanaged_flag (NMDevice *self, - NMUnmanagedFlags flag, - gboolean unmanaged) +nm_device_set_unmanaged_flags_initial (NMDevice *self, + NMUnmanagedFlags flag, + gboolean unmanaged) { NMDevicePrivate *priv; @@ -7642,12 +8846,29 @@ nm_device_set_initial_unmanaged_flag (NMDevice *self, priv = NM_DEVICE_GET_PRIVATE (self); g_return_if_fail (priv->initialized == FALSE); - if (unmanaged) - priv->unmanaged_flags |= flag; - else - priv->unmanaged_flags &= ~flag; + _set_unmanaged_flags (self, flag, unmanaged); +} + +void +nm_device_set_unmanaged_quitting (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gboolean need_deactivate = nm_device_is_activating (self) || + priv->state == NM_DEVICE_STATE_ACTIVATED; + + /* It's OK to block here because we're quitting */ + if (need_deactivate) + _set_state_full (self, NM_DEVICE_STATE_DEACTIVATING, NM_DEVICE_STATE_REASON_NOW_UNMANAGED, TRUE); + + nm_device_set_unmanaged_flags (self, + NM_UNMANAGED_INTERNAL, + TRUE, + need_deactivate ? NM_DEVICE_STATE_REASON_REMOVED + : NM_DEVICE_STATE_REASON_NOW_UNMANAGED); } +/*****************************************************************************/ + void nm_device_set_dhcp_timeout (NMDevice *self, guint32 timeout) { @@ -7670,7 +8891,84 @@ nm_device_set_dhcp_anycast_address (NMDevice *self, const char *addr) priv->dhcp_anycast_address = g_strdup (addr); } -static void +void +nm_device_reapply_settings_immediately (NMDevice *self) +{ + NMConnection *applied_connection; + NMSettingsConnection *settings_connection; + NMDeviceState state; + NMSettingConnection *s_con_settings; + NMSettingConnection *s_con_applied; + const char *zone; + NMMetered metered; + + g_return_if_fail (NM_IS_DEVICE (self)); + + state = nm_device_get_state (self); + if ( state <= NM_DEVICE_STATE_DISCONNECTED + || state > NM_DEVICE_STATE_ACTIVATED) + return; + + applied_connection = nm_device_get_applied_connection (self); + settings_connection = nm_device_get_settings_connection (self); + + if (!nm_settings_connection_has_unmodified_applied_connection (settings_connection, + applied_connection, + NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY)) + return; + + s_con_settings = nm_connection_get_setting_connection ((NMConnection *) settings_connection); + s_con_applied = nm_connection_get_setting_connection (applied_connection); + + if (g_strcmp0 ((zone = nm_setting_connection_get_zone (s_con_settings)), + nm_setting_connection_get_zone (s_con_applied)) != 0) { + + _LOGD (LOGD_DEVICE, "reapply setting: zone = %s%s%s", NM_PRINT_FMT_QUOTE_STRING (zone)); + + g_object_set (G_OBJECT (s_con_applied), + NM_SETTING_CONNECTION_ZONE, zone, + NULL); + + nm_device_update_firewall_zone (self); + } + + if ((metered = nm_setting_connection_get_metered (s_con_settings)) != nm_setting_connection_get_metered (s_con_applied)) { + + _LOGD (LOGD_DEVICE, "reapply setting: metered = %d", (int) metered); + + g_object_set (G_OBJECT (s_con_applied), + NM_SETTING_CONNECTION_METERED, metered, + NULL); + + nm_device_update_metered (self); + } +} + +void +nm_device_update_firewall_zone (NMDevice *self) +{ + NMConnection *applied_connection; + NMSettingConnection *s_con; + + g_return_if_fail (NM_IS_DEVICE (self)); + + applied_connection = nm_device_get_applied_connection (self); + if (!applied_connection) + return; + + s_con = nm_connection_get_setting_connection (applied_connection); + if ( nm_device_get_state (self) == NM_DEVICE_STATE_ACTIVATED + && !nm_device_uses_assumed_connection (self)) { + nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (), + nm_device_get_ip_iface (self), + nm_setting_connection_get_zone (s_con), + FALSE, /* change zone */ + NULL, + NULL); + } +} + +void nm_device_update_metered (NMDevice *self) { #define NM_METERED_INVALID ((NMMetered) -1) @@ -7688,7 +8986,7 @@ nm_device_update_metered (NMDevice *self) value = NM_METERED_UNKNOWN; if (value == NM_METERED_INVALID) { - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); if (connection) { setting = nm_connection_get_setting_connection (connection); if (setting) { @@ -7723,6 +9021,34 @@ nm_device_update_metered (NMDevice *self) } } +static gboolean +_nm_device_check_connection_available (NMDevice *self, + NMConnection *connection, + NMDeviceCheckConAvailableFlags flags, + const char *specific_object) +{ + NMDeviceState state; + + state = nm_device_get_state (self); + if (state < NM_DEVICE_STATE_UNMANAGED) + return FALSE; + if ( state < NM_DEVICE_STATE_UNAVAILABLE + && nm_device_get_unmanaged_flags (self, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT)) + return FALSE; + if ( state < NM_DEVICE_STATE_DISCONNECTED + && !nm_device_is_software (self) + && ( ( !NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST) + && !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) + || ( NM_FLAGS_ANY (flags, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST) + && !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_FOR_USER_REQUEST)))) + return FALSE; + + if (!nm_device_check_connection_compatible (self, connection)) + return FALSE; + + return NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, flags, specific_object); +} + /** * nm_device_check_connection_available(): * @self: the #NMDevice @@ -7744,25 +9070,33 @@ nm_device_check_connection_available (NMDevice *self, NMDeviceCheckConAvailableFlags flags, const char *specific_object) { - NMDeviceState state; + gboolean available; - state = nm_device_get_state (self); - if (state < NM_DEVICE_STATE_UNMANAGED) - return FALSE; - if ( state < NM_DEVICE_STATE_UNAVAILABLE - && nm_device_get_unmanaged_flag (self, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT)) - return FALSE; - if ( state < NM_DEVICE_STATE_DISCONNECTED - && ( ( !NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER) - && !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) - || ( NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER) - && !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER)))) - return FALSE; + available = _nm_device_check_connection_available (self, connection, flags, specific_object); - if (!nm_device_check_connection_compatible (self, connection)) - return FALSE; +#if NM_MORE_ASSERTS >= 2 + { + /* The meaning of the flags is so that *adding* a flag relaxes a condition, thus making + * the device *more* available. Assert against that requirement by testing all the flags. */ + NMDeviceCheckConAvailableFlags i, j, k; + gboolean available_all[NM_DEVICE_CHECK_CON_AVAILABLE_ALL + 1] = { FALSE }; + + for (i = 0; i <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; i++) + available_all[i] = _nm_device_check_connection_available (self, connection, i, specific_object); + + for (i = 0; i <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; i++) { + for (j = 1; j <= NM_DEVICE_CHECK_CON_AVAILABLE_ALL; j <<= 1) { + if (NM_FLAGS_HAS (i, j)) { + k = i & ~j; + nm_assert ( available_all[i] == available_all[k] + || available_all[i]); + } + } + } + } +#endif - return NM_DEVICE_GET_CLASS (self)->check_connection_available (self, connection, flags, specific_object); + return available; } static void @@ -7842,6 +9176,8 @@ nm_device_recheck_available_connections (NMDevice *self) _signal_available_connections_changed (self); } + + available_connection_check_delete_unrealized (self); } /** @@ -7883,29 +9219,44 @@ nm_device_get_available_connections (NMDevice *self, const char *specific_object static void cp_connection_added (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data) { - if (_try_add_available_connection (NM_DEVICE (user_data), connection)) - _signal_available_connections_changed (NM_DEVICE (user_data)); + NMDevice *self = user_data; + + g_return_if_fail (NM_IS_DEVICE (self)); + + if (_try_add_available_connection (self, connection)) + _signal_available_connections_changed (self); } static void cp_connection_removed (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data) { - if (_del_available_connection (NM_DEVICE (user_data), connection)) - _signal_available_connections_changed (NM_DEVICE (user_data)); + NMDevice *self = user_data; + + g_return_if_fail (NM_IS_DEVICE (self)); + + if (_del_available_connection (self, connection)) { + _signal_available_connections_changed (self); + available_connection_check_delete_unrealized (self); + } } static void cp_connection_updated (NMConnectionProvider *cp, NMConnection *connection, gpointer user_data) { + NMDevice *self = user_data; gboolean added, deleted; + g_return_if_fail (NM_IS_DEVICE (self)); + /* FIXME: don't remove it from the hash if it's just going to get re-added */ - deleted = _del_available_connection (NM_DEVICE (user_data), connection); - added = _try_add_available_connection (NM_DEVICE (user_data), connection); + deleted = _del_available_connection (self, connection); + added = _try_add_available_connection (self, connection); /* Only signal if the connection was removed OR added, but not both */ - if (added != deleted) - _signal_available_connections_changed (NM_DEVICE (user_data)); + if (added != deleted) { + _signal_available_connections_changed (self); + available_connection_check_delete_unrealized (self); + } } gboolean @@ -7979,12 +9330,13 @@ gboolean nm_device_remove_pending_action (NMDevice *self, const char *action, gboolean assert_is_pending) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - GSList *iter; + GSList *iter, *next; guint count = 0; g_return_val_if_fail (action, FALSE); - for (iter = priv->pending_actions; iter; iter = iter->next) { + for (iter = priv->pending_actions; iter; iter = next) { + next = iter->next; if (!strcmp (action, iter->data)) { _LOGD (LOGD_DEVICE, "remove_pending_action (%d): '%s'", count + g_slist_length (iter->next), /* length excluding 'iter' */ @@ -8017,23 +9369,6 @@ nm_device_has_pending_action (NMDevice *self) /***********************************************************/ -static void -_cleanup_ip_pre (NMDevice *self, CleanupType cleanup_type) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - priv->ip4_state = priv->ip6_state = IP_NONE; - nm_device_queued_ip_config_change_clear (self); - - dhcp4_cleanup (self, cleanup_type, FALSE); - arp_cleanup (self); - dhcp6_cleanup (self, cleanup_type, FALSE); - linklocal6_cleanup (self); - addrconf6_cleanup (self); - dnsmasq_cleanup (self); - aipd_cleanup (self); -} - static void _cancel_activation (NMDevice *self) { @@ -8041,15 +9376,17 @@ _cancel_activation (NMDevice *self) /* Clean up when device was deactivated during call to firewall */ if (priv->fw_call) { - nm_firewall_manager_cancel_call (nm_firewall_manager_get (), priv->fw_call); + nm_firewall_manager_cancel_call (priv->fw_call); + g_warn_if_fail (!priv->fw_call); priv->fw_call = NULL; } + priv->fw_ready = FALSE; ip_check_gw_ping_cleanup (self); /* Break the activation chain */ - activation_source_clear (self, TRUE, AF_INET); - activation_source_clear (self, TRUE, AF_INET6); + activation_source_clear (self, AF_INET); + activation_source_clear (self, AF_INET6); } static void @@ -8059,19 +9396,22 @@ _cleanup_generic_pre (NMDevice *self, CleanupType cleanup_type) _cancel_activation (self); - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); if ( cleanup_type == CLEANUP_TYPE_DECONFIGURE && connection && !nm_device_uses_assumed_connection (self)) { nm_firewall_manager_remove_from_zone (nm_firewall_manager_get (), nm_device_get_ip_iface (self), + NULL, + NULL, NULL); } /* Clear any queued transitions */ nm_device_queued_state_clear (self); - _cleanup_ip_pre (self, cleanup_type); + _cleanup_ip4_pre (self, cleanup_type); + _cleanup_ip6_pre (self, cleanup_type); } static void @@ -8098,6 +9438,8 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) priv->v4_commit_first_time = TRUE; priv->v6_commit_first_time = TRUE; + priv->linklocal6_dad_counter = 0; + /* Clean up IP configs; this does not actually deconfigure the * interface; the caller must flush routes and addresses explicitly. */ @@ -8107,15 +9449,18 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) g_clear_object (&priv->dev_ip4_config); g_clear_object (&priv->ext_ip4_config); g_clear_object (&priv->wwan_ip4_config); - g_clear_object (&priv->vpn4_config); g_clear_object (&priv->ip4_config); g_clear_object (&priv->con_ip6_config); g_clear_object (&priv->ac_ip6_config); g_clear_object (&priv->ext_ip6_config); - g_clear_object (&priv->vpn6_config); g_clear_object (&priv->wwan_ip6_config); g_clear_object (&priv->ip6_config); + g_slist_free_full (priv->vpn4_configs, g_object_unref); + priv->vpn4_configs = NULL; + g_slist_free_full (priv->vpn6_configs, g_object_unref); + priv->vpn6_configs = NULL; + clear_act_request (self); /* Clear legacy IPv4 address property */ @@ -8177,11 +9522,9 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean nm_device_master_release_slaves (self); /* slave: mark no longer enslaved */ - if (nm_platform_link_get_master (NM_PLATFORM_GET, priv->ifindex) <= 0) { - g_clear_object (&priv->master); - priv->enslaved = FALSE; - g_object_notify (G_OBJECT (self), NM_DEVICE_MASTER); - } + if ( priv->master + && nm_platform_link_get_master (NM_PLATFORM_GET, priv->ifindex) <= 0) + nm_device_master_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); /* Take out any entries in the routing table and any IP address the device had. */ ifindex = nm_device_get_ip_ifindex (self); @@ -8190,6 +9533,9 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean nm_platform_address_flush (NM_PLATFORM_GET, ifindex); } + if (priv->lldp_listener) + nm_lldp_listener_stop (priv->lldp_listener); + nm_device_update_metered (self); _cleanup_generic_post (self, cleanup_type); } @@ -8241,13 +9587,14 @@ nm_device_spawn_iface_helper (NMDevice *self) const char *method; GPtrArray *argv; gs_free char *dhcp4_address = NULL; + char *logging_backend; if (priv->state != NM_DEVICE_STATE_ACTIVATED) return; if (!nm_device_can_assume_connections (self)) return; - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); g_assert (connection); argv = g_ptr_array_sized_new (10); @@ -8259,6 +9606,17 @@ nm_device_spawn_iface_helper (NMDevice *self) g_ptr_array_add (argv, g_strdup ("--uuid")); g_ptr_array_add (argv, g_strdup (nm_connection_get_uuid (connection))); + logging_backend = nm_config_get_is_debug (nm_config_get ()) + ? g_strdup ("debug") + : nm_config_data_get_value (NM_CONFIG_GET_DATA_ORIG, + NM_CONFIG_KEYFILE_GROUP_LOGGING, + NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND, + NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY); + if (logging_backend) { + g_ptr_array_add (argv, g_strdup ("--logging-backend")); + g_ptr_array_add (argv, logging_backend); + } + dhcp4_address = find_dhcp4_address (self); method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); @@ -8278,7 +9636,7 @@ nm_device_spawn_iface_helper (NMDevice *self) g_ptr_array_add (argv, g_strdup ("--dhcp4-required")); if (priv->dhcp4_client) { - const char *hostname; + const char *hostname, *fqdn; GBytes *client_id; client_id = nm_dhcp_client_get_client_id (priv->dhcp4_client); @@ -8294,6 +9652,12 @@ nm_device_spawn_iface_helper (NMDevice *self) g_ptr_array_add (argv, g_strdup ("--dhcp4-hostname")); g_ptr_array_add (argv, g_strdup (hostname)); } + + fqdn = nm_dhcp_client_get_fqdn (priv->dhcp4_client); + if (fqdn) { + g_ptr_array_add (argv, g_strdup ("--dhcp4-fqdn")); + g_ptr_array_add (argv, g_strdup (fqdn)); + } } configured = TRUE; @@ -8325,6 +9689,9 @@ nm_device_spawn_iface_helper (NMDevice *self) g_ptr_array_add (argv, hex_iid); } + g_ptr_array_add (argv, g_strdup ("--addr-gen-mode")); + g_ptr_array_add (argv, g_strdup_printf ("%d", nm_setting_ip6_config_get_addr_gen_mode (NM_SETTING_IP6_CONFIG (s_ip6)))); + configured = TRUE; } @@ -8398,15 +9765,14 @@ deactivate_async_ready (NMDevice *self, /* If operation cancelled, just return */ if ( g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) || (priv->deactivating_cancellable && g_cancellable_is_cancelled (priv->deactivating_cancellable))) { - nm_log_warn (LOGD_DEVICE, "Deactivation (%s) cancelled", - nm_device_get_iface (self)); + _LOGW (LOGD_DEVICE, "Deactivation cancelled"); } /* In every other case, transition to the DISCONNECTED state */ else { - if (error) - nm_log_warn (LOGD_DEVICE, "Deactivation (%s) failed: %s", - nm_device_get_iface (self), - error->message); + if (error) { + _LOGW (LOGD_DEVICE, "Deactivation failed: %s", + error->message); + } nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, reason); } @@ -8453,17 +9819,21 @@ _set_state_full (NMDevice *self, NMDeviceStateReason reason, gboolean quitting) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv; NMDeviceState old_state; NMActRequest *req; gboolean no_firmware = FALSE; - NMConnection *connection; + NMSettingsConnection *connection; + NMConnection *applied_connection; + + g_return_if_fail (NM_IS_DEVICE (self)); + + priv = NM_DEVICE_GET_PRIVATE (self); /* Track re-entry */ g_warn_if_fail (priv->in_state_changed == FALSE); - priv->in_state_changed = TRUE; - g_return_if_fail (NM_IS_DEVICE (self)); + old_state = priv->state; /* Do nothing if state isn't changing, but as a special case allow * re-setting UNAVAILABLE if the device is missing firmware so that we @@ -8471,14 +9841,16 @@ _set_state_full (NMDevice *self, */ if ( (priv->state == state) && !(state == NM_DEVICE_STATE_UNAVAILABLE && priv->firmware_missing)) { - priv->in_state_changed = FALSE; + _LOGD (LOGD_DEVICE, "device state change: %s -> %s (reason '%s') [%d %d %d] (skip due to missing firmware)", + state_to_string (old_state), + state_to_string (state), + reason_to_string (reason), + old_state, + state, + reason); return; } - old_state = priv->state; - priv->state = state; - priv->state_reason = reason; - _LOGI (LOGD_DEVICE, "device state change: %s -> %s (reason '%s') [%d %d %d]", state_to_string (old_state), state_to_string (state), @@ -8487,6 +9859,11 @@ _set_state_full (NMDevice *self, state, reason); + priv->in_state_changed = TRUE; + + priv->state = state; + priv->state_reason = reason; + /* Clear any queued transitions */ nm_device_queued_state_clear (self); @@ -8573,7 +9950,8 @@ _set_state_full (NMDevice *self, /* Clean up any half-done IP operations if the device's layer2 * finds out it needs authentication during IP config. */ - _cleanup_ip_pre (self, CLEANUP_TYPE_DECONFIGURE); + _cleanup_ip4_pre (self, CLEANUP_TYPE_DECONFIGURE); + _cleanup_ip6_pre (self, CLEANUP_TYPE_DECONFIGURE); } break; default: @@ -8587,7 +9965,7 @@ _set_state_full (NMDevice *self, g_object_notify (G_OBJECT (self), NM_DEVICE_STATE); g_object_notify (G_OBJECT (self), NM_DEVICE_STATE_REASON); - g_signal_emit_by_name (self, "state-changed", state, old_state, reason); + g_signal_emit_by_name (self, NM_DEVICE_STATE_CHANGED, state, old_state, reason); /* Post-process the event after internal notification */ @@ -8622,13 +10000,15 @@ _set_state_full (NMDevice *self, if (quitting) { nm_dispatcher_call_sync (DISPATCHER_ACTION_PRE_DOWN, - nm_act_request_get_connection (req), + nm_act_request_get_settings_connection (req), + nm_act_request_get_applied_connection (req), self); } else { priv->dispatcher.post_state = NM_DEVICE_STATE_DISCONNECTED; priv->dispatcher.post_state_reason = reason; if (!nm_dispatcher_call (DISPATCHER_ACTION_PRE_DOWN, - nm_act_request_get_connection (req), + nm_act_request_get_settings_connection (req), + nm_act_request_get_applied_connection (req), self, deactivate_dispatcher_complete, self, @@ -8659,7 +10039,10 @@ _set_state_full (NMDevice *self, case NM_DEVICE_STATE_ACTIVATED: _LOGI (LOGD_DEVICE, "Activation: successful, device activated."); nm_device_update_metered (self); - nm_dispatcher_call (DISPATCHER_ACTION_UP, nm_act_request_get_connection (req), self, NULL, NULL, NULL); + nm_dispatcher_call (DISPATCHER_ACTION_UP, + nm_act_request_get_settings_connection (req), + nm_act_request_get_applied_connection (req), + self, NULL, NULL, NULL); break; case NM_DEVICE_STATE_FAILED: /* Usually upon failure the activation chain is interrupted in @@ -8678,10 +10061,10 @@ _set_state_full (NMDevice *self, break; } - connection = nm_device_get_connection (self); + connection = nm_device_get_settings_connection (self); _LOGW (LOGD_DEVICE | LOGD_WIFI, "Activation: failed for connection '%s'", - connection ? nm_connection_get_id (connection) : ""); + connection ? nm_settings_connection_get_id (connection) : ""); /* Notify any slaves of the unexpected failure */ nm_device_master_release_slaves (self); @@ -8691,11 +10074,8 @@ _set_state_full (NMDevice *self, * failed (zero timestamp), connections that succeeded (non-zero timestamp), * and those we haven't tried yet (no timestamp). */ - if (connection && !nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (connection), NULL)) { - nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (connection), - (guint64) 0, - TRUE); - } + if (connection && !nm_settings_connection_get_timestamp (connection, NULL)) + nm_settings_connection_update_timestamp (connection, (guint64) 0, TRUE); /* Schedule the transition to DISCONNECTED. The device can't transition * immediately because we can't change states again from the state @@ -8704,7 +10084,28 @@ _set_state_full (NMDevice *self, nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE); break; case NM_DEVICE_STATE_IP_CHECK: - nm_device_start_ip_check (self); + /* Now that IP config has completed, check if the firewall + * zone must be set again for the IP interface. + */ + applied_connection = nm_device_get_applied_connection (self); + + if ( applied_connection + && priv->ifindex != priv->ip_ifindex + && !nm_device_uses_assumed_connection (self)) { + NMSettingConnection *s_con; + const char *zone; + + s_con = nm_connection_get_setting_connection (applied_connection); + zone = nm_setting_connection_get_zone (s_con); + g_assert (!priv->fw_call); + priv->fw_call = nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (), + nm_device_get_ip_iface (self), + zone, + FALSE, + fw_change_zone_cb_ip_check, + self); + } else + nm_device_start_ip_check (self); /* IP-related properties are only valid when the device has IP configuration; * now that it does, ensure their change notifications are emitted. @@ -8724,10 +10125,17 @@ _set_state_full (NMDevice *self, if ( (old_state == NM_DEVICE_STATE_ACTIVATED || old_state == NM_DEVICE_STATE_DEACTIVATING) && (state != NM_DEVICE_STATE_DEACTIVATING)) { - if (quitting) - nm_dispatcher_call_sync (DISPATCHER_ACTION_DOWN, nm_act_request_get_connection (req), self); - else - nm_dispatcher_call (DISPATCHER_ACTION_DOWN, nm_act_request_get_connection (req), self, NULL, NULL, NULL); + if (quitting) { + nm_dispatcher_call_sync (DISPATCHER_ACTION_DOWN, + nm_act_request_get_settings_connection (req), + nm_act_request_get_applied_connection (req), + self); + } else { + nm_dispatcher_call (DISPATCHER_ACTION_DOWN, + nm_act_request_get_settings_connection (req), + nm_act_request_get_applied_connection (req), + self, NULL, NULL, NULL); + } } /* IP-related properties are only valid when the device has IP configuration. @@ -8836,7 +10244,7 @@ nm_device_queued_state_clear (NMDevice *self) if (priv->queued_state.id) { _LOGD (LOGD_DEVICE, "clearing queued state transition (id %d)", priv->queued_state.id); - g_source_remove (priv->queued_state.id); + nm_clear_g_source (&priv->queued_state.id); nm_device_remove_pending_action (self, queued_state_to_string (priv->queued_state.state), TRUE); } memset (&priv->queued_state, 0, sizeof (priv->queued_state)); @@ -8864,20 +10272,26 @@ nm_device_get_hw_address (NMDevice *self) return priv->hw_addr_len ? priv->hw_addr : NULL; } -static void +void nm_device_update_hw_address (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); int ifindex = nm_device_get_ifindex (self); const guint8 *hwaddr; gsize hwaddrlen = 0; + static const guint8 zero_hwaddr[ETH_ALEN]; if (ifindex <= 0) return; hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &hwaddrlen); + if ( priv->type == NM_DEVICE_TYPE_ETHERNET + && nm_utils_hwaddr_matches (hwaddr, hwaddrlen, zero_hwaddr, sizeof (zero_hwaddr))) + hwaddrlen = 0; + if (hwaddrlen) { + priv->hw_addr_len = hwaddrlen; if (!priv->hw_addr || !nm_utils_hwaddr_matches (priv->hw_addr, -1, hwaddr, hwaddrlen)) { g_free (priv->hw_addr); priv->hw_addr = nm_utils_hwaddr_ntoa (hwaddr, hwaddrlen); @@ -8889,12 +10303,39 @@ nm_device_update_hw_address (NMDevice *self) /* Invalid or no hardware address */ if (priv->hw_addr_len != 0) { g_clear_pointer (&priv->hw_addr, g_free); + priv->hw_addr_len = 0; _LOGD (LOGD_HW | LOGD_DEVICE, "previous hardware address is no longer valid"); g_object_notify (G_OBJECT (self), NM_DEVICE_HW_ADDRESS); } } - priv->hw_addr_len = hwaddrlen; +} + +void +nm_device_update_initial_hw_address (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->hw_addr_len) { + priv->initial_hw_addr = g_strdup (priv->hw_addr); + _LOGD (LOGD_DEVICE | LOGD_HW, "read initial MAC address %s", priv->initial_hw_addr); + + if (priv->ifindex > 0) { + guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; + size_t len = 0; + + if (nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len)) { + g_warn_if_fail (len == priv->hw_addr_len); + priv->perm_hw_addr = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len); + _LOGD (LOGD_DEVICE | LOGD_HW, "read permanent MAC address %s", + priv->perm_hw_addr); + } else { + /* Fall back to current address */ + _LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address"); + priv->perm_hw_addr = g_strdup (priv->hw_addr); + } + } + } } gboolean @@ -9004,7 +10445,7 @@ spec_match_list (NMDevice *self, const GSList *specs) break; } } - if (priv->hw_addr_len) { + if (priv->hw_addr_len && priv->hw_addr) { m = nm_match_spec_hwaddr (specs, priv->hw_addr); matched = MAX (matched, m); } @@ -9021,12 +10462,34 @@ spec_match_list (NMDevice *self, const GSList *specs) /***********************************************************/ -#define DEFAULT_AUTOCONNECT TRUE +static const char * +_activation_func_to_string (ActivationHandleFunc func) +{ +#define FUNC_TO_STRING_CHECK_AND_RETURN(func, f) \ + G_STMT_START { \ + if ((func) == (f)) \ + return #f; \ + } G_STMT_END + FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage1_device_prepare); + FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage2_device_config); + FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage3_ip_config_start); + FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage4_ip4_config_timeout); + FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage4_ip6_config_timeout); + FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage5_ip4_config_commit); + FUNC_TO_STRING_CHECK_AND_RETURN (func, activate_stage5_ip6_config_commit); + g_return_val_if_reached ("unknown"); +} + +/***********************************************************/ static void nm_device_init (NMDevice *self) { - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDevicePrivate *priv; + + priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_DEVICE, NMDevicePrivate); + + self->priv = priv; priv->type = NM_DEVICE_TYPE_UNKNOWN; priv->capabilities = NM_DEVICE_CAP_NM_SUPPORTED; @@ -9052,133 +10515,50 @@ constructor (GType type, GObjectConstructParam *construct_params) { GObject *object; + GObjectClass *klass; NMDevice *self; NMDevicePrivate *priv; - NMPlatform *platform; - static guint32 id = 0; + const NMPlatformLink *pllink; - object = G_OBJECT_CLASS (nm_device_parent_class)->constructor (type, - n_construct_params, - construct_params); + klass = G_OBJECT_CLASS (nm_device_parent_class); + object = klass->constructor (type, n_construct_params, construct_params); if (!object) return NULL; self = NM_DEVICE (object); priv = NM_DEVICE_GET_PRIVATE (self); - _LOGD (LOGD_DEVICE, "constructor(): %s, kernel ifindex %d", G_OBJECT_TYPE_NAME (self), priv->ifindex); + if (priv->iface) { + pllink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, priv->iface); - if (!priv->iface) { - _LOGE (LOGD_DEVICE, "No device interface provided, ignoring"); - goto error; - } - - if (!priv->udi) { - /* Use a placeholder UDI until we get a real one */ - priv->udi = g_strdup_printf ("/virtual/device/placeholder/%d", id++); + if (pllink && link_type_compatible (self, pllink->type, NULL, NULL)) { + priv->ifindex = pllink->ifindex; + priv->up = NM_FLAGS_HAS (pllink->flags, IFF_UP); + } } - if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities) - priv->capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self); + return object; +} - if (priv->ifindex > 0) { - priv->physical_port_id = nm_platform_link_get_physical_port_id (NM_PLATFORM_GET, priv->ifindex); - priv->dev_id = nm_platform_link_get_dev_id (NM_PLATFORM_GET, priv->ifindex); - if (nm_platform_link_is_software (NM_PLATFORM_GET, priv->ifindex)) - priv->capabilities |= NM_DEVICE_CAP_IS_SOFTWARE; - priv->mtu = nm_platform_link_get_mtu (NM_PLATFORM_GET, priv->ifindex); +static void +constructed (GObject *object) +{ + NMDevice *self = NM_DEVICE (object); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMPlatform *platform; - nm_platform_link_get_driver_info (NM_PLATFORM_GET, - priv->ifindex, - NULL, - &priv->driver_version, - &priv->firmware_version); - } + platform = nm_platform_get (); if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities) priv->capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self); /* Watch for external IP config changes */ - platform = nm_platform_get (); g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, G_CALLBACK (device_ipx_changed), self); g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, G_CALLBACK (device_ipx_changed), self); g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (device_ipx_changed), self); g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (device_ipx_changed), self); g_signal_connect (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (link_changed_cb), self); - /* trigger initial ip config change to initialize ip-config */ - priv->queued_ip4_config_id = g_idle_add (queued_ip4_config_change, self); - priv->queued_ip6_config_id = g_idle_add (queued_ip6_config_change, self); - - if (nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET)) { - int ip_ifindex = nm_device_get_ip_ifindex (self); - - if (ip_ifindex > 0) - priv->nm_ipv6ll = nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, ip_ifindex); - } - - return object; - -error: - g_object_unref (self); - return NULL; -} - -static void -constructed (GObject *object) -{ - NMDevice *self = NM_DEVICE (object); - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - int master; - - nm_device_update_hw_address (self); - - if (priv->hw_addr_len) { - priv->initial_hw_addr = g_strdup (priv->hw_addr); - _LOGD (LOGD_DEVICE | LOGD_HW, "read initial MAC address %s", priv->initial_hw_addr); - - if (priv->ifindex > 0) { - guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; - size_t len = 0; - - if (nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len)) { - g_warn_if_fail (len == priv->hw_addr_len); - priv->perm_hw_addr = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len); - _LOGD (LOGD_DEVICE | LOGD_HW, "read permanent MAC address %s", - priv->perm_hw_addr); - } else { - /* Fall back to current address */ - _LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address"); - priv->perm_hw_addr = g_strdup (priv->hw_addr); - } - } - } - - /* Note: initial hardware address must be read before calling get_ignore_carrier() */ - if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { - NMConfig *config = nm_config_get (); - - priv->ignore_carrier = nm_config_data_get_ignore_carrier (nm_config_get_data (config), self); - g_signal_connect (G_OBJECT (config), - NM_CONFIG_SIGNAL_CONFIG_CHANGED, - G_CALLBACK (config_changed_update_ignore_carrier), - self); - - check_carrier (self); - _LOGD (LOGD_HW, - "carrier is %s%s", - priv->carrier ? "ON" : "OFF", - priv->ignore_carrier ? " (but ignored)" : ""); - } else { - /* Fake online link when carrier detection is not available. */ - priv->carrier = TRUE; - } - - /* Enslave ourselves */ - master = nm_platform_link_get_master (NM_PLATFORM_GET, priv->ifindex); - if (master) - device_set_master (self, master); - priv->con_provider = nm_connection_provider_get (); g_assert (priv->con_provider); g_signal_connect (priv->con_provider, @@ -9206,6 +10586,8 @@ constructed (GObject *object) } G_OBJECT_CLASS (nm_device_parent_class)->constructed (object); + + _LOGD (LOGD_DEVICE, "constructed (%s)", G_OBJECT_TYPE_NAME (self)); } static void @@ -9215,7 +10597,7 @@ dispose (GObject *object) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMPlatform *platform; - _LOGD (LOGD_DEVICE, "dispose(): %s", G_OBJECT_TYPE_NAME (self)); + _LOGD (LOGD_DEVICE, "disposing"); g_signal_handlers_disconnect_by_func (nm_config_get (), config_changed_update_ignore_carrier, self); @@ -9233,15 +10615,10 @@ dispose (GObject *object) g_hash_table_remove_all (priv->ip6_saved_properties); - if (priv->recheck_assume_id) { - g_source_remove (priv->recheck_assume_id); - priv->recheck_assume_id = 0; - } + nm_clear_g_source (&priv->recheck_assume_id); + nm_clear_g_source (&priv->recheck_available.call_id); - if (priv->recheck_available.call_id) { - g_source_remove (priv->recheck_available.call_id); - priv->recheck_available.call_id = 0; - } + nm_clear_g_source (&priv->check_delete_unrealized_id); link_disconnect_action_cancel (self); @@ -9265,7 +10642,22 @@ dispose (GObject *object) nm_clear_g_source (&priv->device_link_changed_id); nm_clear_g_source (&priv->device_ip_link_changed_id); + if (priv->lldp_listener) { + g_signal_handlers_disconnect_by_func (priv->lldp_listener, + G_CALLBACK (lldp_neighbors_changed), + self); + nm_lldp_listener_stop (priv->lldp_listener); + g_clear_object (&priv->lldp_listener); + } + G_OBJECT_CLASS (nm_device_parent_class)->dispose (object); + + if (nm_clear_g_source (&priv->queued_state.id)) { + /* FIXME: we'd expect the queud_state to be alredy cleared and this statement + * not being necessary. Add this check here to hopefully investigate crash + * rh#1270247. */ + g_return_if_reached (); + } } static void @@ -9280,9 +10672,9 @@ finalize (GObject *object) g_free (priv->perm_hw_addr); g_free (priv->initial_hw_addr); g_slist_free_full (priv->pending_actions, g_free); + g_slist_free_full (priv->dad6_failed_addrs, g_free); g_clear_pointer (&priv->physical_port_id, g_free); g_free (priv->udi); - g_free (priv->path); g_free (priv->iface); g_free (priv->ip_iface); g_free (priv->driver); @@ -9304,25 +10696,11 @@ set_property (GObject *object, guint prop_id, { NMDevice *self = NM_DEVICE (object); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - NMPlatformLink *platform_device; const char *hw_addr, *p; guint count; + gboolean val_bool; switch (prop_id) { - case PROP_PLATFORM_DEVICE: - platform_device = g_value_get_pointer (value); - if (platform_device) { - g_free (priv->udi); - priv->udi = g_strdup (nm_platform_link_get_udi (NM_PLATFORM_GET, platform_device->ifindex)); - g_free (priv->iface); - priv->iface = g_strdup (platform_device->name); - priv->ifindex = platform_device->ifindex; - priv->up = NM_FLAGS_HAS (platform_device->flags, IFF_UP); - g_free (priv->driver); - priv->driver = g_strdup (platform_device->driver); - priv->platform_link_initialized = platform_device->initialized; - } - break; case PROP_UDI: if (g_value_get_string (value)) { g_free (priv->udi); @@ -9330,13 +10708,9 @@ set_property (GObject *object, guint prop_id, } break; case PROP_IFACE: - if (g_value_get_string (value)) { - g_free (priv->iface); - priv->iface = g_value_dup_string (value); - priv->ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->iface); - if (priv->ifindex > 0) - priv->up = nm_platform_link_is_up (NM_PLATFORM_GET, priv->ifindex); - } + /* construct only */ + g_return_if_fail (!priv->iface); + priv->iface = g_value_dup_string (value); break; case PROP_DRIVER: if (g_value_get_string (value)) { @@ -9358,16 +10732,32 @@ set_property (GObject *object, guint prop_id, case PROP_IP4_ADDRESS: priv->ip4_address = g_value_get_uint (value); break; + case PROP_MANAGED: + val_bool = g_value_get_boolean (value); + priv->managed_touched_by_user = TRUE; + nm_device_set_unmanaged_flags (self, + NM_UNMANAGED_USER | (val_bool ? NM_UNMANAGED_DEFAULT : NM_UNMANAGED_NONE), + !val_bool, + NM_DEVICE_STATE_REASON_USER_REQUESTED); + break; case PROP_AUTOCONNECT: nm_device_set_autoconnect (self, g_value_get_boolean (value)); break; case PROP_FIRMWARE_MISSING: priv->firmware_missing = g_value_get_boolean (value); break; + case PROP_NM_PLUGIN_MISSING: + priv->nm_plugin_missing = g_value_get_boolean (value); + break; case PROP_DEVICE_TYPE: g_return_if_fail (priv->type == NM_DEVICE_TYPE_UNKNOWN); priv->type = g_value_get_uint (value); break; + case PROP_LINK_TYPE: + /* construct only */ + g_return_if_fail (priv->link_type == NM_LINK_TYPE_NONE); + priv->link_type = g_value_get_uint (value); + break; case PROP_TYPE_DESC: g_free (priv->type_desc); priv->type_desc = g_value_dup_string (value); @@ -9411,18 +10801,16 @@ set_property (GObject *object, guint prop_id, } } -#define DBUS_TYPE_STATE_REASON_STRUCT (dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID)) - static void get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) + GValue *value, GParamSpec *pspec) { NMDevice *self = NM_DEVICE (object); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - const char *ac_path = NULL; GPtrArray *array; GHashTableIter iter; NMConnection *connection; + GVariantBuilder array_builder; switch (prop_id) { case PROP_UDI: @@ -9462,44 +10850,33 @@ get_property (GObject *object, guint prop_id, g_value_set_uint (value, priv->mtu); break; case PROP_IP4_CONFIG: - if (ip_config_valid (priv->state) && priv->ip4_config) - g_value_set_boxed (value, nm_ip4_config_get_dbus_path (priv->ip4_config)); - else - g_value_set_boxed (value, "/"); + nm_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->ip4_config : NULL); break; case PROP_DHCP4_CONFIG: - if (ip_config_valid (priv->state) && priv->dhcp4_config) - g_value_set_boxed (value, nm_dhcp4_config_get_dbus_path (priv->dhcp4_config)); - else - g_value_set_boxed (value, "/"); + nm_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->dhcp4_config : NULL); break; case PROP_IP6_CONFIG: - if (ip_config_valid (priv->state) && priv->ip6_config) - g_value_set_boxed (value, nm_ip6_config_get_dbus_path (priv->ip6_config)); - else - g_value_set_boxed (value, "/"); + nm_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->ip6_config : NULL); break; case PROP_DHCP6_CONFIG: - if (ip_config_valid (priv->state) && priv->dhcp6_config) - g_value_set_boxed (value, nm_dhcp6_config_get_dbus_path (priv->dhcp6_config)); - else - g_value_set_boxed (value, "/"); + nm_utils_g_value_set_object_path (value, ip_config_valid (priv->state) ? priv->dhcp6_config : NULL); break; case PROP_STATE: g_value_set_uint (value, priv->state); break; case PROP_STATE_REASON: - g_value_take_boxed (value, dbus_g_type_specialized_construct (DBUS_TYPE_STATE_REASON_STRUCT)); - dbus_g_type_struct_set (value, 0, priv->state, 1, priv->state_reason, G_MAXUINT); + g_value_take_variant (value, + g_variant_new ("(uu)", priv->state, priv->state_reason)); break; case PROP_ACTIVE_CONNECTION: - if (priv->act_request) - ac_path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (priv->act_request)); - g_value_set_boxed (value, ac_path ? ac_path : "/"); + nm_utils_g_value_set_object_path (value, priv->act_request); break; case PROP_DEVICE_TYPE: g_value_set_uint (value, priv->type); break; + case PROP_LINK_TYPE: + g_value_set_uint (value, priv->link_type); + break; case PROP_MANAGED: g_value_set_boolean (value, nm_device_get_managed (self)); break; @@ -9509,6 +10886,9 @@ get_property (GObject *object, guint prop_id, case PROP_FIRMWARE_MISSING: g_value_set_boolean (value, priv->firmware_missing); break; + case PROP_NM_PLUGIN_MISSING: + g_value_set_boolean (value, priv->nm_plugin_missing); + break; case PROP_TYPE_DESC: g_value_set_string (value, priv->type_desc); break; @@ -9520,7 +10900,8 @@ get_property (GObject *object, guint prop_id, g_hash_table_iter_init (&iter, priv->available_connections); while (g_hash_table_iter_next (&iter, (gpointer) &connection, NULL)) g_ptr_array_add (array, g_strdup (nm_connection_get_path (connection))); - g_value_take_boxed (value, array); + g_ptr_array_add (array, NULL); + g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE)); break; case PROP_PHYSICAL_PORT_ID: g_value_set_string (value, priv->physical_port_id); @@ -9529,7 +10910,7 @@ get_property (GObject *object, guint prop_id, g_value_set_boolean (value, priv->is_master); break; case PROP_MASTER: - g_value_set_object (value, priv->master); + g_value_set_object (value, nm_device_get_master (self)); break; case PROP_HW_ADDRESS: g_value_set_string (value, priv->hw_addr); @@ -9540,6 +10921,37 @@ get_property (GObject *object, guint prop_id, case PROP_METERED: g_value_set_uint (value, priv->metered); break; + case PROP_LLDP_NEIGHBORS: + if (priv->lldp_listener) + g_value_set_variant (value, nm_lldp_listener_get_neighbors (priv->lldp_listener)); + else { + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); + g_value_take_variant (value, g_variant_builder_end (&array_builder)); + } + break; + case PROP_REAL: + g_value_set_boolean (value, nm_device_is_real (self)); + break; + case PROP_SLAVES: { + GSList *slave_iter; + char **slave_list; + guint i; + + slave_list = g_new (char *, g_slist_length (priv->slaves) + 1); + for (slave_iter = priv->slaves, i = 0; slave_iter; slave_iter = slave_iter->next) { + SlaveInfo *info = slave_iter->data; + const char *path; + + if (!NM_DEVICE_GET_PRIVATE (info->slave)->is_enslaved) + continue; + path = nm_exported_object_get_path ((NMExportedObject *) info->slave); + if (path) + slave_list[i++] = g_strdup (path); + } + slave_list[i] = NULL; + g_value_take_boxed (value, slave_list); + break; + } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -9550,9 +10962,12 @@ static void nm_device_class_init (NMDeviceClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (klass); g_type_class_add_private (object_class, sizeof (NMDevicePrivate)); + exported_object_class->export_path = NM_DBUS_PATH "/Devices/%u"; + /* Virtual methods */ object_class->dispose = dispose; object_class->finalize = finalize; @@ -9578,6 +10993,8 @@ nm_device_class_init (NMDeviceClass *klass) klass->check_connection_compatible = check_connection_compatible; klass->check_connection_available = check_connection_available; klass->can_unmanaged_external_down = can_unmanaged_external_down; + klass->realize_start_notify = realize_start_notify; + klass->unrealize_notify = unrealize_notify; klass->is_up = is_up; klass->bring_up = bring_up; klass->take_down = take_down; @@ -9585,12 +11002,6 @@ nm_device_class_init (NMDeviceClass *klass) klass->get_ip_iface_identifier = get_ip_iface_identifier; /* Properties */ - g_object_class_install_property - (object_class, PROP_PLATFORM_DEVICE, - g_param_spec_pointer (NM_DEVICE_PLATFORM_DEVICE, "", "", - G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - g_object_class_install_property (object_class, PROP_UDI, g_param_spec_string (NM_DEVICE_UDI, "", "", @@ -9663,31 +11074,31 @@ nm_device_class_init (NMDeviceClass *klass) g_object_class_install_property (object_class, PROP_IP4_CONFIG, - g_param_spec_boxed (NM_DEVICE_IP4_CONFIG, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_DEVICE_IP4_CONFIG, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_DHCP4_CONFIG, - g_param_spec_boxed (NM_DEVICE_DHCP4_CONFIG, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_DEVICE_DHCP4_CONFIG, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_IP6_CONFIG, - g_param_spec_boxed (NM_DEVICE_IP6_CONFIG, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_DEVICE_IP6_CONFIG, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_DHCP6_CONFIG, - g_param_spec_boxed (NM_DEVICE_DHCP6_CONFIG, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_DEVICE_DHCP6_CONFIG, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_STATE, @@ -9698,17 +11109,18 @@ nm_device_class_init (NMDeviceClass *klass) g_object_class_install_property (object_class, PROP_STATE_REASON, - g_param_spec_boxed (NM_DEVICE_STATE_REASON, "", "", - DBUS_TYPE_STATE_REASON_STRUCT, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_variant (NM_DEVICE_STATE_REASON, "", "", + G_VARIANT_TYPE ("(uu)"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_ACTIVE_CONNECTION, - g_param_spec_boxed (NM_DEVICE_ACTIVE_CONNECTION, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_DEVICE_ACTIVE_CONNECTION, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_DEVICE_TYPE, @@ -9717,11 +11129,18 @@ nm_device_class_init (NMDeviceClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property + (object_class, PROP_LINK_TYPE, + g_param_spec_uint (NM_DEVICE_LINK_TYPE, "", "", + 0, G_MAXUINT32, NM_LINK_TYPE_NONE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, PROP_MANAGED, g_param_spec_boolean (NM_DEVICE_MANAGED, "", "", FALSE, - G_PARAM_READABLE | + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property @@ -9738,6 +11157,13 @@ nm_device_class_init (NMDeviceClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property + (object_class, PROP_NM_PLUGIN_MISSING, + g_param_spec_boolean (NM_DEVICE_NM_PLUGIN_MISSING, "", "", + FALSE, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, PROP_TYPE_DESC, g_param_spec_string (NM_DEVICE_TYPE_DESC, "", "", @@ -9764,7 +11190,7 @@ nm_device_class_init (NMDeviceClass *klass) g_object_class_install_property (object_class, PROP_AVAILABLE_CONNECTIONS, g_param_spec_boxed (NM_DEVICE_AVAILABLE_CONNECTIONS, "", "", - DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, + G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -9808,7 +11234,7 @@ nm_device_class_init (NMDeviceClass *klass) * * Whether the connection is metered. * - * Since: 1.0.6 + * Since: 1.2 **/ g_object_class_install_property (object_class, PROP_METERED, @@ -9817,9 +11243,31 @@ nm_device_class_init (NMDeviceClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property + (object_class, PROP_LLDP_NEIGHBORS, + g_param_spec_variant (NM_DEVICE_LLDP_NEIGHBORS, "", "", + G_VARIANT_TYPE ("aa{sv}"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_REAL, + g_param_spec_boolean (NM_DEVICE_REAL, "", "", + FALSE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_SLAVES, + g_param_spec_boxed (NM_DEVICE_SLAVES, "", "", + G_TYPE_STRV, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + /* Signals */ signals[STATE_CHANGED] = - g_signal_new ("state-changed", + g_signal_new (NM_DEVICE_STATE_CHANGED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NMDeviceClass, state_changed), @@ -9840,8 +11288,8 @@ nm_device_class_init (NMDeviceClass *klass) G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, - /* dbus-glib context, connection, permission, allow_interaction, callback, user_data */ - G_TYPE_NONE, 6, G_TYPE_POINTER, G_TYPE_POINTER, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER, G_TYPE_POINTER); + /* context, connection, permission, allow_interaction, callback, user_data */ + G_TYPE_NONE, 6, G_TYPE_DBUS_METHOD_INVOCATION, NM_TYPE_CONNECTION, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_POINTER, G_TYPE_POINTER); signals[IP4_CONFIG_CHANGED] = g_signal_new (NM_DEVICE_IP4_CONFIG_CHANGED, @@ -9878,17 +11326,10 @@ nm_device_class_init (NMDeviceClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 0); - signals[LINK_INITIALIZED] = - g_signal_new (NM_DEVICE_LINK_INITIALIZED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 0); - - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_object_info); - - dbus_g_error_domain_register (NM_DEVICE_ERROR, NULL, NM_TYPE_DEVICE_ERROR); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_SKELETON, + "Reapply", impl_device_reapply, + "Disconnect", impl_device_disconnect, + "Delete", impl_device_delete, + NULL); } - diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 49cef8e1..e173b2db 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -22,13 +22,11 @@ #ifndef __NETWORKMANAGER_DEVICE_H__ #define __NETWORKMANAGER_DEVICE_H__ -#include -#include -#include #include +#include "nm-exported-object.h" #include "nm-dbus-interface.h" -#include "nm-types.h" +#include "nm-default.h" #include "nm-connection.h" #include "nm-rfkill-manager.h" #include "NetworkManagerUtils.h" @@ -51,14 +49,23 @@ #define NM_DEVICE_STATE_REASON "state-reason" #define NM_DEVICE_ACTIVE_CONNECTION "active-connection" #define NM_DEVICE_DEVICE_TYPE "device-type" /* ugh */ +#define NM_DEVICE_LINK_TYPE "link-type" #define NM_DEVICE_MANAGED "managed" #define NM_DEVICE_AUTOCONNECT "autoconnect" #define NM_DEVICE_FIRMWARE_MISSING "firmware-missing" +#define NM_DEVICE_NM_PLUGIN_MISSING "nm-plugin-missing" #define NM_DEVICE_AVAILABLE_CONNECTIONS "available-connections" #define NM_DEVICE_PHYSICAL_PORT_ID "physical-port-id" #define NM_DEVICE_MTU "mtu" #define NM_DEVICE_HW_ADDRESS "hw-address" #define NM_DEVICE_METERED "metered" +#define NM_DEVICE_LLDP_NEIGHBORS "lldp-neighbors" +#define NM_DEVICE_REAL "real" + +/* the "slaves" property is internal in the parent class, but exposed + * by the derived classes NMDeviceBond, NMDeviceBridge and NMDeviceTeam. + * It is thus important that the property name matches. */ +#define NM_DEVICE_SLAVES "slaves" /* partially internal */ #define NM_DEVICE_TYPE_DESC "type-desc" /* Internal only */ #define NM_DEVICE_RFKILL_TYPE "rfkill-type" /* Internal only */ @@ -74,6 +81,7 @@ #define NM_DEVICE_REMOVED "removed" #define NM_DEVICE_RECHECK_AUTO_ACTIVATE "recheck-auto-activate" #define NM_DEVICE_RECHECK_ASSUME "recheck-assume" +#define NM_DEVICE_STATE_CHANGED "state-changed" #define NM_DEVICE_LINK_INITIALIZED "link-initialized" G_BEGIN_DECLS @@ -100,28 +108,34 @@ typedef enum { /*< skip >*/ NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST = _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER | _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP, - __NM_DEVICE_CHECK_CON_AVAILABLE_ALL, - NM_DEVICE_CHECK_CON_AVAILABLE_ALL = (((__NM_DEVICE_CHECK_CON_AVAILABLE_ALL - 1) << 1) - 1), + NM_DEVICE_CHECK_CON_AVAILABLE_ALL = (1L << 2) - 1, } NMDeviceCheckConAvailableFlags; +struct _NMDevicePrivate; + struct _NMDevice { - GObject parent; + NMExportedObject parent; + + /* private */ + struct _NMDevicePrivate *priv; }; /* The flags have an relaxing meaning, that means, specifying more flags, can make * a device appear more available. It can never make a device less available. */ typedef enum { /*< skip >*/ NM_DEVICE_CHECK_DEV_AVAILABLE_NONE = 0, - NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER = (1L << 0), - __NM_DEVICE_CHECK_DEV_AVAILABLE_ALL, - NM_DEVICE_CHECK_DEV_AVAILABLE_ALL = (((__NM_DEVICE_CHECK_DEV_AVAILABLE_ALL - 1) << 1) - 1), + _NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER = (1L << 0), + NM_DEVICE_CHECK_DEV_AVAILABLE_FOR_USER_REQUEST = _NM_DEVICE_CHECK_DEV_AVAILABLE_IGNORE_CARRIER, + + NM_DEVICE_CHECK_DEV_AVAILABLE_ALL = (1L << 1) - 1, } NMDeviceCheckDevAvailableFlags; typedef struct { - GObjectClass parent; + NMExportedObjectClass parent; const char *connection_type; + const NMLinkType *link_types; void (*state_changed) (NMDevice *device, NMDeviceState new_state, @@ -130,6 +144,48 @@ typedef struct { void (* link_changed) (NMDevice *self, NMPlatformLink *info); + /** + * create_and_realize(): + * @self: the #NMDevice + * @connection: the #NMConnection being activated + * @parent: the parent #NMDevice, if any + * @out_plink: on success, a backing kernel network device if one exists. + * The returned pointer is owned by platform and only valid until the + * next platform operation. + * @error: location to store error, or %NULL + * + * Create any backing resources (kernel devices, etc) required for this + * device to activate @connection. If the device is backed by a kernel + * network device, that device should be returned in @out_plink after + * being created. + * + * Returns: %TRUE on success, %FALSE on error + */ + gboolean (*create_and_realize) (NMDevice *self, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error); + + /** + * realize_start_notify(): + * @self: the #NMDevice + * @plink: the #NMPlatformLink if backed by a kernel netdevice + * + * Hook for derived classes to be notfied during realize_start_setup() + * and perform additional setup. + */ + void (*realize_start_notify) (NMDevice *self, const NMPlatformLink *plink); + + /** + * unrealize_notify(): + * @self: the #NMDevice + * + * Hook for derived classes to clear any properties that depend on backing resources + * (kernel devices, etc). This is called by nm_device_unrealize() during unrealization. + */ + void (*unrealize_notify) (NMDevice *self); + /* Hardware state (IFF_UP) */ gboolean (*can_unmanaged_external_down) (NMDevice *self); gboolean (*is_up) (NMDevice *self); @@ -155,7 +211,7 @@ typedef struct { /* Checks whether the connection is compatible with the device using * only the devices type and characteristics. Does not use any live - * network information like WiFi/WiMAX scan lists etc. + * network information like WiFi scan lists etc. */ gboolean (* check_connection_compatible) (NMDevice *self, NMConnection *connection); @@ -186,11 +242,11 @@ typedef struct { NMActStageReturn (* act_stage2_config) (NMDevice *self, NMDeviceStateReason *reason); NMActStageReturn (* act_stage3_ip4_config_start) (NMDevice *self, - NMIP4Config **out_config, - NMDeviceStateReason *reason); + NMIP4Config **out_config, + NMDeviceStateReason *reason); NMActStageReturn (* act_stage3_ip6_config_start) (NMDevice *self, - NMIP6Config **out_config, - NMDeviceStateReason *reason); + NMIP6Config **out_config, + NMDeviceStateReason *reason); NMActStageReturn (* act_stage4_ip4_config_timeout) (NMDevice *self, NMDeviceStateReason *reason); NMActStageReturn (* act_stage4_ip6_config_timeout) (NMDevice *self, @@ -229,13 +285,15 @@ typedef struct { NMConnection *connection, gboolean configure); - gboolean (* release_slave) (NMDevice *self, + void (* release_slave) (NMDevice *self, NMDevice *slave, gboolean configure); gboolean (* have_any_ready_slaves) (NMDevice *self, const GSList *slaves); + void (* notify_new_device_added) (NMDevice *self, NMDevice *new_device); + /** * component_added: * @self: the #NMDevice @@ -258,23 +316,21 @@ typedef struct { NMConnection * (* new_default_connection) (NMDevice *self); } NMDeviceClass; - typedef void (*NMDeviceAuthRequestFunc) (NMDevice *device, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, + NMAuthSubject *subject, GError *error, gpointer user_data); GType nm_device_get_type (void); -const char * nm_device_get_path (NMDevice *dev); -void nm_device_dbus_export (NMDevice *device); - void nm_device_finish_init (NMDevice *device); const char * nm_device_get_udi (NMDevice *dev); const char * nm_device_get_iface (NMDevice *dev); int nm_device_get_ifindex (NMDevice *dev); gboolean nm_device_is_software (NMDevice *dev); +gboolean nm_device_is_real (NMDevice *dev); const char * nm_device_get_ip_iface (NMDevice *dev); int nm_device_get_ip_ifindex(NMDevice *dev); const char * nm_device_get_driver (NMDevice *dev); @@ -282,6 +338,7 @@ const char * nm_device_get_driver_version (NMDevice *dev); const char * nm_device_get_type_desc (NMDevice *dev); const char * nm_device_get_type_description (NMDevice *dev); NMDeviceType nm_device_get_device_type (NMDevice *dev); +NMLinkType nm_device_get_link_type (NMDevice *dev); NMMetered nm_device_get_metered (NMDevice *dev); int nm_device_get_priority (NMDevice *dev); @@ -296,21 +353,28 @@ NMDhcp4Config * nm_device_get_dhcp4_config (NMDevice *dev); NMDhcp6Config * nm_device_get_dhcp6_config (NMDevice *dev); NMIP4Config * nm_device_get_ip4_config (NMDevice *dev); -void nm_device_set_vpn4_config (NMDevice *dev, NMIP4Config *config); +void nm_device_replace_vpn4_config (NMDevice *dev, + NMIP4Config *old, + NMIP4Config *config); NMIP6Config * nm_device_get_ip6_config (NMDevice *dev); -void nm_device_set_vpn6_config (NMDevice *dev, NMIP6Config *config); +void nm_device_replace_vpn6_config (NMDevice *dev, + NMIP6Config *old, + NMIP6Config *config); void nm_device_capture_initial_config (NMDevice *dev); /* Master */ -GSList * nm_device_master_get_slaves (NMDevice *dev); +gboolean nm_device_is_master (NMDevice *dev); /* Slave */ NMDevice * nm_device_get_master (NMDevice *dev); -NMActRequest * nm_device_get_act_request (NMDevice *dev); -NMConnection * nm_device_get_connection (NMDevice *dev); +NMActRequest * nm_device_get_act_request (NMDevice *dev); +NMSettingsConnection * nm_device_get_settings_connection (NMDevice *dev); +NMConnection * nm_device_get_applied_connection (NMDevice *dev); +gboolean nm_device_has_unmodified_applied_connection (NMDevice *self, + NMSettingCompareFlags compare_flags); void nm_device_removed (NMDevice *dev); @@ -335,6 +399,7 @@ gboolean nm_device_complete_connection (NMDevice *device, GError **error); gboolean nm_device_check_connection_compatible (NMDevice *device, NMConnection *connection); +gboolean nm_device_check_slave_connection_compatible (NMDevice *device, NMConnection *connection); gboolean nm_device_uses_assumed_connection (NMDevice *device); @@ -356,23 +421,27 @@ RfKillType nm_device_get_rfkill_type (NMDevice *device); /** * NMUnmanagedFlags: * @NM_UNMANAGED_NONE: placeholder value - * @NM_UNMANAGED_DEFAULT: %TRUE when unmanaged by default (ie, Generic devices) * @NM_UNMANAGED_INTERNAL: %TRUE when unmanaged by internal decision (ie, * because NM is sleeping or not managed for some other reason) - * @NM_UNMANAGED_USER: %TRUE when unmanaged by user decision (via unmanaged-specs) * @NM_UNMANAGED_PARENT: %TRUE when unmanaged due to parent device being unmanaged - * @NM_UNMANAGED_EXTERNAL_DOWN: %TRUE when unmanaged because !IFF_UP and not created by NM + * @NM_UNMANAGED_LOOPBACK: %TRUE for unmanaging loopback device * @NM_UNMANAGED_PLATFORM_INIT: %TRUE when unmanaged because platform link not * yet initialized + * @NM_UNMANAGED_USER: %TRUE when unmanaged by user decision (via unmanaged-specs) + * @NM_UNMANAGED_DEFAULT: %TRUE when unmanaged by default (ie, Generic devices) + * @NM_UNMANAGED_EXTERNAL_DOWN: %TRUE when unmanaged because !IFF_UP and not created by NM */ -typedef enum { - NM_UNMANAGED_NONE = 0x00, - NM_UNMANAGED_DEFAULT = 0x01, - NM_UNMANAGED_INTERNAL = 0x02, - NM_UNMANAGED_USER = 0x04, - NM_UNMANAGED_PARENT = 0x08, - NM_UNMANAGED_EXTERNAL_DOWN = 0x10, - NM_UNMANAGED_PLATFORM_INIT = 0x20, +typedef enum { /*< skip >*/ + NM_UNMANAGED_NONE = 0, + + NM_UNMANAGED_INTERNAL = (1LL << 0), + NM_UNMANAGED_PARENT = (1LL << 1), + NM_UNMANAGED_LOOPBACK = (1LL << 2), + NM_UNMANAGED_PLATFORM_INIT = (1LL << 3), + NM_UNMANAGED_USER = (1LL << 4), + + NM_UNMANAGED_DEFAULT = (1LL << 8), + NM_UNMANAGED_EXTERNAL_DOWN = (1LL << 11), /* Boundary value */ __NM_UNMANAGED_LAST, @@ -381,26 +450,37 @@ typedef enum { } NMUnmanagedFlags; gboolean nm_device_get_managed (NMDevice *device); -gboolean nm_device_get_unmanaged_flag (NMDevice *device, NMUnmanagedFlags flag); -void nm_device_set_unmanaged (NMDevice *device, - NMUnmanagedFlags flag, - gboolean unmanaged, - NMDeviceStateReason reason); +NMUnmanagedFlags nm_device_get_unmanaged_flags (NMDevice *device, NMUnmanagedFlags flag); +void nm_device_set_unmanaged_flags (NMDevice *device, + NMUnmanagedFlags flag, + gboolean unmanaged, + NMDeviceStateReason reason); +void nm_device_set_unmanaged_flags_by_device_spec (NMDevice *self, const GSList *unmanaged_specs); +void nm_device_set_unmanaged_flags_initial (NMDevice *device, + NMUnmanagedFlags flag, + gboolean unmanaged); void nm_device_set_unmanaged_quitting (NMDevice *device); -void nm_device_set_initial_unmanaged_flag (NMDevice *device, - NMUnmanagedFlags flag, - gboolean unmanaged); gboolean nm_device_get_is_nm_owned (NMDevice *device); -void nm_device_set_nm_owned (NMDevice *device); gboolean nm_device_has_capability (NMDevice *self, NMDeviceCapabilities caps); -gboolean nm_device_get_autoconnect (NMDevice *device); +gboolean nm_device_realize_start (NMDevice *device, + const NMPlatformLink *plink, + gboolean *out_compatible, + GError **error); +void nm_device_realize_finish (NMDevice *self, + const NMPlatformLink *plink); +gboolean nm_device_create_and_realize (NMDevice *self, + NMConnection *connection, + NMDevice *parent, + GError **error); +gboolean nm_device_unrealize (NMDevice *device, + gboolean remove_resources, + GError **error); -void nm_device_handle_autoip4_event (NMDevice *self, - const char *event, - const char *address); +gboolean nm_device_get_autoconnect (NMDevice *device); +void nm_device_set_autoconnect (NMDevice *device, gboolean autoconnect); void nm_device_state_changed (NMDevice *device, NMDeviceState state, @@ -411,8 +491,11 @@ void nm_device_queue_state (NMDevice *self, NMDeviceStateReason reason); gboolean nm_device_get_firmware_missing (NMDevice *self); +gboolean nm_device_get_nm_plugin_missing (NMDevice *self); +void nm_device_set_nm_plugin_missing (NMDevice *self, + gboolean missing); -void nm_device_steal_connection (NMDevice *device, NMConnection *connection); +void nm_device_steal_connection (NMDevice *device, NMSettingsConnection *connection); void nm_device_queue_activation (NMDevice *device, NMActRequest *req); @@ -430,6 +513,7 @@ gboolean nm_device_check_connection_available (NMDevice *device, NMDeviceCheckConAvailableFlags flags, const char *specific_object); +void nm_device_notify_new_device_added (NMDevice *self, NMDevice *new_device); gboolean nm_device_notify_component_added (NMDevice *device, GObject *component); gboolean nm_device_owns_iface (NMDevice *device, const char *iface); @@ -441,9 +525,20 @@ const NMPlatformIP6Route *nm_device_get_ip6_default_route (NMDevice *self, gbool void nm_device_spawn_iface_helper (NMDevice *self); -G_END_DECLS +void nm_device_reapply_settings_immediately (NMDevice *self); + +void nm_device_update_firewall_zone (NMDevice *self); +void nm_device_update_metered (NMDevice *self); +void nm_device_reactivate_ip4_config (NMDevice *device, + NMSettingIPConfig *s_ip4_old, + NMSettingIPConfig *s_ip4_new); +void nm_device_reactivate_ip6_config (NMDevice *device, + NMSettingIPConfig *s_ip6_old, + NMSettingIPConfig *s_ip6_new); -/* For testing only */ -extern const char* nm_device_autoipd_helper_path; +void nm_device_update_hw_address (NMDevice *self); +void nm_device_update_initial_hw_address (NMDevice *self); + +G_END_DECLS #endif /* NM_DEVICE_H */ diff --git a/src/devices/nm-lldp-listener.c b/src/devices/nm-lldp-listener.c new file mode 100644 index 00000000..91181292 --- /dev/null +++ b/src/devices/nm-lldp-listener.c @@ -0,0 +1,648 @@ +/* -*- 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) 2015 Red Hat, Inc. + */ + +#include "config.h" + +#include + +#include "sd-lldp.h" +#include "lldp.h" +#include "nm-lldp-listener.h" +#include "nm-platform.h" +#include "nm-utils.h" + +#define MAX_NEIGHBORS 4096 +#define MIN_UPDATE_INTERVAL 2 + +typedef struct { + char *iface; + int ifindex; + sd_lldp *lldp_handle; + GHashTable *lldp_neighbors; + guint timer; + guint num_pending_events; + GVariant *variant; +} NMLldpListenerPrivate; + +enum { + PROP_0, + PROP_NEIGHBORS, + + LAST_PROP +}; + +G_DEFINE_TYPE (NMLldpListener, nm_lldp_listener, G_TYPE_OBJECT) + +#define NM_LLDP_LISTENER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_LLDP_LISTENER, NMLldpListenerPrivate)) + +typedef struct { + guint8 chassis_id_type; + guint8 port_id_type; + char *chassis_id; + char *port_id; + + int dest; + + GHashTable *tlvs; +} LLDPNeighbor; + +static void process_lldp_neighbors (NMLldpListener *self); + +static void +gvalue_destroy (gpointer data) +{ + GValue *value = (GValue *) data; + + g_value_unset (value); + g_slice_free (GValue, value); +} + +static GValue * +gvalue_new_nstr (const char *str, guint16 len) +{ + GValue *value; + + value = g_slice_new0 (GValue); + g_value_init (value, G_TYPE_STRING); + g_value_take_string (value, strndup (str, len)); + return value; +} + +static GValue * +gvalue_new_uint (guint val) +{ + GValue *value; + + value = g_slice_new0 (GValue); + g_value_init (value, G_TYPE_UINT); + g_value_set_uint (value, val); + return value; +} + +static guint +lldp_neighbor_id_hash (gconstpointer ptr) +{ + const LLDPNeighbor *neigh = ptr; + + return g_str_hash (neigh->chassis_id) ^ + g_str_hash (neigh->port_id) ^ + neigh->chassis_id_type ^ + (neigh->port_id_type * 33); +} + +static gboolean +lldp_neighbor_id_equal (gconstpointer a, gconstpointer b) +{ + const LLDPNeighbor *x = a, *y = b; + + return x->chassis_id_type == y->chassis_id_type && + x->port_id_type == y->port_id_type && + !g_strcmp0 (x->chassis_id, y->chassis_id) && + !g_strcmp0 (x->port_id, y->port_id); +} + +static void +lldp_neighbor_free (gpointer data) +{ + LLDPNeighbor *neighbor = data; + + if (neighbor) { + g_free (neighbor->chassis_id); + g_free (neighbor->port_id); + g_hash_table_unref (neighbor->tlvs); + g_free (neighbor); + } +} + +static gboolean +lldp_neighbor_equal (LLDPNeighbor *a, LLDPNeighbor *b) +{ + GHashTableIter iter; + gpointer k, v; + + g_return_val_if_fail (a && a->tlvs, FALSE); + g_return_val_if_fail (b && b->tlvs, FALSE); + + if ( a->chassis_id_type != b->chassis_id_type + || a->port_id_type != b->port_id_type + || a->dest != b->dest + || g_strcmp0 (a->chassis_id, b->chassis_id) + || g_strcmp0 (a->port_id, b->port_id)) + return FALSE; + + if (g_hash_table_size (a->tlvs) != g_hash_table_size (b->tlvs)) + return FALSE; + + g_hash_table_iter_init (&iter, a->tlvs); + while (g_hash_table_iter_next (&iter, &k, &v)) { + GValue *value_a, *value_b; + + value_a = v; + value_b = g_hash_table_lookup (b->tlvs, k); + + if (!value_b) + return FALSE; + + g_return_val_if_fail (G_VALUE_TYPE (value_a) == G_VALUE_TYPE (value_b), FALSE); + + if (G_VALUE_HOLDS_STRING (value_a)) { + if (g_strcmp0 (g_value_get_string (value_a), g_value_get_string (value_b))) + return FALSE; + } else if (G_VALUE_HOLDS_UINT (value_a)) { + if (g_value_get_uint (value_a) != g_value_get_uint (value_b)) + return FALSE; + } else + g_return_val_if_reached (FALSE); + } + + return TRUE; +} + +static gboolean +lldp_hash_table_equal (GHashTable *a, GHashTable *b) +{ + GHashTableIter iter; + gpointer val; + + g_return_val_if_fail (a, FALSE); + g_return_val_if_fail (b, FALSE); + + if (g_hash_table_size (a) != g_hash_table_size (b)) + return FALSE; + + g_hash_table_iter_init (&iter, a); + while (g_hash_table_iter_next (&iter, NULL, &val)) { + LLDPNeighbor *neigh_a, *neigh_b; + + neigh_a = val; + neigh_b = g_hash_table_lookup (b, val); + + if (!neigh_b) + return FALSE; + + if (!lldp_neighbor_equal (neigh_a, neigh_b)) + return FALSE; + } + + return TRUE; +} + +static gboolean +lldp_timeout (gpointer user_data) +{ + NMLldpListener *self = NM_LLDP_LISTENER (user_data); + NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE (self); + + priv->timer = 0; + + if (priv->num_pending_events) + process_lldp_neighbors (self); + + return G_SOURCE_REMOVE; +} + +static void +process_lldp_neighbors (NMLldpListener *self) +{ + NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE (self); + sd_lldp_packet **packets = NULL; + GHashTable *hash; + int num, i; + + num = sd_lldp_get_packets (priv->lldp_handle, &packets); + if (num < 0) { + nm_log_dbg (LOGD_DEVICE, "LLDP: error %d retrieving neighbor packets for %s", + num, priv->iface); + return; + } + + hash = g_hash_table_new_full (lldp_neighbor_id_hash, lldp_neighbor_id_equal, + lldp_neighbor_free, NULL); + + for (i = 0; packets && i < num; i++) { + uint8_t chassis_id_type, port_id_type, *chassis_id, *port_id, data8; + uint16_t chassis_id_len, port_id_len, len, data16; + LLDPNeighbor *neigh; + GValue *value; + char *str; + int r; + + if (i >= MAX_NEIGHBORS) + goto next_packet; + + r = sd_lldp_packet_read_chassis_id (packets[i], &chassis_id_type, + &chassis_id, &chassis_id_len); + if (r < 0) + goto next_packet; + + r = sd_lldp_packet_read_port_id (packets[i], &port_id_type, + &port_id, &port_id_len); + if (r < 0) + goto next_packet; + + neigh = g_malloc0 (sizeof (LLDPNeighbor)); + neigh->tlvs = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gvalue_destroy); + neigh->chassis_id_type = chassis_id_type; + neigh->port_id_type = port_id_type; + sd_lldp_packet_get_destination_type (packets[i], &neigh->dest); + + if (chassis_id_len < 1) { + lldp_neighbor_free (neigh); + goto next_packet; + } + + switch (chassis_id_type) { + case LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS: + case LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME: + case LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED: + case LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT: + neigh->chassis_id = strndup ((char *) chassis_id, chassis_id_len); + break; + case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: + neigh->chassis_id = nm_utils_hwaddr_ntoa (chassis_id, chassis_id_len); + break; + default: + nm_log_dbg (LOGD_DEVICE, "LLDP: unsupported chassis ID type %d", chassis_id_type); + lldp_neighbor_free (neigh); + goto next_packet; + } + + if (port_id_len < 1) { + lldp_neighbor_free (neigh); + goto next_packet; + } + + switch (port_id_type) { + case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: + case LLDP_PORT_SUBTYPE_INTERFACE_NAME: + case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: + case LLDP_PORT_SUBTYPE_PORT_COMPONENT: + neigh->port_id = strndup ((char *) port_id, port_id_len); + break; + case LLDP_PORT_SUBTYPE_MAC_ADDRESS: + neigh->port_id = nm_utils_hwaddr_ntoa (port_id, port_id_len); + break; + default: + nm_log_dbg (LOGD_DEVICE, "LLDP: unsupported port ID type %d", port_id_type); + lldp_neighbor_free (neigh); + goto next_packet; + } + + if (sd_lldp_packet_read_port_description (packets[i], &str, &len) == 0) { + value = gvalue_new_nstr (str, len); + g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_PORT_DESCRIPTION, value); + } + + if (sd_lldp_packet_read_system_name (packets[i], &str, &len) == 0) { + value = gvalue_new_nstr (str, len); + g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_SYSTEM_NAME, value); + } + + if (sd_lldp_packet_read_system_description (packets[i], &str, &len) == 0) { + value = gvalue_new_nstr (str, len); + g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_SYSTEM_DESCRIPTION, value); + } + + if (sd_lldp_packet_read_system_capability (packets[i], &data16) == 0) { + value = gvalue_new_uint (data16); + g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_SYSTEM_CAPABILITIES, value); + } + + if (sd_lldp_packet_read_port_vlan_id (packets[i], &data16) == 0) { + value = gvalue_new_uint (data16); + g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PVID, value); + } + + if (sd_lldp_packet_read_port_protocol_vlan_id (packets[i], &data8, &data16) == 0) { + value = gvalue_new_uint (data16); + g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PPVID, value); + + value = gvalue_new_uint (data8); + g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_PPVID_FLAGS, value); + } + + if (sd_lldp_packet_read_vlan_name (packets[i], &data16, &str, &len) == 0) { + value = gvalue_new_uint (data16); + g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_VID, value); + + value = gvalue_new_nstr (str, len); + g_hash_table_insert (neigh->tlvs, NM_LLDP_ATTR_IEEE_802_1_VLAN_NAME, value); + } + + nm_log_dbg (LOGD_DEVICE, "LLDP: new neigh: CHASSIS='%s' PORT='%s'", + neigh->chassis_id, neigh->port_id); + + g_hash_table_add (hash, neigh); +next_packet: + sd_lldp_packet_unref (packets[i]); + } + + g_free (packets); + + if (lldp_hash_table_equal (priv->lldp_neighbors, hash)) { + g_hash_table_destroy (hash); + } else { + g_hash_table_destroy (priv->lldp_neighbors); + priv->lldp_neighbors = hash; + nm_clear_g_variant (&priv->variant); + g_object_notify (G_OBJECT (self), NM_LLDP_LISTENER_NEIGHBORS); + } + + /* Since the processing of the neighbor list is potentially + * expensive when there are many neighbors, coalesce multiple + * events arriving in short time. + */ + priv->timer = g_timeout_add_seconds (MIN_UPDATE_INTERVAL, lldp_timeout, self); + priv->num_pending_events = 0; +} + +static void +lldp_event_handler (sd_lldp *lldp, int event, void *userdata) +{ + NMLldpListener *self = userdata; + NMLldpListenerPrivate *priv; + + g_return_if_fail (NM_IS_LLDP_LISTENER (self)); + priv = NM_LLDP_LISTENER_GET_PRIVATE (self); + + if (priv->timer > 0) { + priv->num_pending_events++; + return; + } + + process_lldp_neighbors (self); +} + +gboolean +nm_lldp_listener_start (NMLldpListener *self, int ifindex, const char *iface, + const guint8 *mac, guint mac_len, GError **error) +{ + NMLldpListenerPrivate *priv; + int ret; + + g_return_val_if_fail (NM_IS_LLDP_LISTENER (self), FALSE); + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (iface, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + + priv = NM_LLDP_LISTENER_GET_PRIVATE (self); + + if (priv->lldp_handle) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "already running"); + return FALSE; + } + + if (!mac || mac_len != ETH_ALEN) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "unsupported device"); + return FALSE; + } + + ret = sd_lldp_new (ifindex, iface, (struct ether_addr *) mac, &priv->lldp_handle); + if (ret) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "initialization failed"); + return FALSE; + } + + ret = sd_lldp_attach_event (priv->lldp_handle, NULL, 0); + if (ret) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "attach event failed"); + goto err_free; + } + + ret = sd_lldp_set_callback (priv->lldp_handle, lldp_event_handler, self); + if (ret) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "set callback failed"); + goto err; + } + + ret = sd_lldp_start (priv->lldp_handle); + if (ret) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED, + "start failed"); + goto err; + } + + priv->ifindex = ifindex; + priv->iface = strdup (iface); + return TRUE; + +err: + sd_lldp_detach_event (priv->lldp_handle); +err_free: + sd_lldp_unref (priv->lldp_handle); + priv->lldp_handle = NULL; + return FALSE; +} + +void +nm_lldp_listener_stop (NMLldpListener *self) +{ + NMLldpListenerPrivate *priv; + guint size; + + g_return_if_fail (NM_IS_LLDP_LISTENER (self)); + priv = NM_LLDP_LISTENER_GET_PRIVATE (self); + + if (priv->lldp_handle) { + sd_lldp_stop (priv->lldp_handle); + sd_lldp_detach_event (priv->lldp_handle); + sd_lldp_unref (priv->lldp_handle); + g_clear_pointer (&priv->iface, g_free); + priv->lldp_handle = NULL; + + size = g_hash_table_size (priv->lldp_neighbors); + g_hash_table_remove_all (priv->lldp_neighbors); + if (size) { + nm_clear_g_variant (&priv->variant); + g_object_notify (G_OBJECT (self), NM_LLDP_LISTENER_NEIGHBORS); + } + } + + nm_clear_g_source (&priv->timer); +} + +gboolean +nm_lldp_listener_is_running (NMLldpListener *self) +{ + NMLldpListenerPrivate *priv; + + g_return_val_if_fail (NM_IS_LLDP_LISTENER (self), FALSE); + + priv = NM_LLDP_LISTENER_GET_PRIVATE (self); + return !!priv->lldp_handle; +} + +GVariant * +nm_lldp_listener_get_neighbors (NMLldpListener *self) +{ + GVariantBuilder array_builder, neigh_builder; + GHashTableIter iter; + NMLldpListenerPrivate *priv; + LLDPNeighbor *neigh; + char *dest_str = NULL; + + priv = NM_LLDP_LISTENER_GET_PRIVATE (self); + + if (priv->variant) + goto out; + + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); + g_hash_table_iter_init (&iter, priv->lldp_neighbors); + + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &neigh)) { + GHashTableIter val_iter; + gpointer key, val; + + g_variant_builder_init (&neigh_builder, G_VARIANT_TYPE ("a{sv}")); + + g_variant_builder_add (&neigh_builder, "{sv}", + NM_LLDP_ATTR_CHASSIS_ID_TYPE, + g_variant_new_uint32 (neigh->chassis_id_type)); + g_variant_builder_add (&neigh_builder, "{sv}", + NM_LLDP_ATTR_CHASSIS_ID, + g_variant_new_string (neigh->chassis_id)); + g_variant_builder_add (&neigh_builder, "{sv}", + NM_LLDP_ATTR_PORT_ID_TYPE, + g_variant_new_uint32 (neigh->port_id_type)); + g_variant_builder_add (&neigh_builder, "{sv}", + NM_LLDP_ATTR_PORT_ID, + g_variant_new_string (neigh->port_id)); + + switch (neigh->dest) { + case SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE: + dest_str = NM_LLDP_DEST_NEAREST_BRIDGE; + break; + case SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE: + dest_str = NM_LLDP_DEST_NEAREST_NON_TPMR_BRIDGE; + break; + case SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE: + dest_str = NM_LLDP_DEST_NEAREST_CUSTOMER_BRIDGE; + break; + } + + if (dest_str) { + g_variant_builder_add (&neigh_builder, "{sv}", + NM_LLDP_ATTR_DESTINATION, + g_variant_new_string (dest_str)); + } + + g_hash_table_iter_init (&val_iter, neigh->tlvs); + while (g_hash_table_iter_next (&val_iter, &key, &val)) { + GValue *item = val; + + if (G_VALUE_HOLDS_STRING (item)) { + g_variant_builder_add (&neigh_builder, "{sv}", + key, + g_variant_new_string (g_value_get_string (item))); + } else if (G_VALUE_HOLDS_UINT (item)) { + g_variant_builder_add (&neigh_builder, "{sv}", + key, + g_variant_new_uint32 (g_value_get_uint (item))); + } + } + + g_variant_builder_add (&array_builder, "a{sv}", &neigh_builder); + } + + priv->variant = g_variant_ref_sink (g_variant_builder_end (&array_builder)); + +out: + return priv->variant; +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMLldpListener *self = NM_LLDP_LISTENER (object); + + switch (prop_id) { + case PROP_NEIGHBORS: + g_value_set_variant (value, nm_lldp_listener_get_neighbors (self)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_lldp_listener_init (NMLldpListener *self) +{ + NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE (self); + + priv->lldp_neighbors = g_hash_table_new_full (lldp_neighbor_id_hash, + lldp_neighbor_id_equal, + lldp_neighbor_free, NULL); +} + +NMLldpListener * +nm_lldp_listener_new (void) +{ + return (NMLldpListener *) g_object_new (NM_TYPE_LLDP_LISTENER, NULL); +} + +static void +dispose (GObject *object) +{ + nm_lldp_listener_stop (NM_LLDP_LISTENER (object)); + + G_OBJECT_CLASS (nm_lldp_listener_parent_class)->dispose (object); +} + +static void +finalize (GObject *object) +{ + NMLldpListener *self = NM_LLDP_LISTENER (object); + NMLldpListenerPrivate *priv = NM_LLDP_LISTENER_GET_PRIVATE (self); + + nm_lldp_listener_stop (self); + g_hash_table_unref (priv->lldp_neighbors); + + nm_clear_g_variant (&priv->variant); + + G_OBJECT_CLASS (nm_lldp_listener_parent_class)->finalize (object); +} + +static void +nm_lldp_listener_class_init (NMLldpListenerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (NMLldpListenerPrivate)); + + object_class->dispose = dispose; + object_class->finalize = finalize; + object_class->get_property = get_property; + + g_object_class_install_property + (object_class, PROP_NEIGHBORS, + g_param_spec_variant (NM_LLDP_LISTENER_NEIGHBORS, "", "", + G_VARIANT_TYPE ("aa{sv}"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); +} + diff --git a/src/devices/nm-lldp-listener.h b/src/devices/nm-lldp-listener.h new file mode 100644 index 00000000..492752c1 --- /dev/null +++ b/src/devices/nm-lldp-listener.h @@ -0,0 +1,57 @@ +/* -*- 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) 2015 Red Hat, Inc. + */ + +#ifndef __NM_LLDP_LISTENER__ +#define __NM_LLDP_LISTENER__ + +#include "nm-glib.h" +#include "nm-types.h" + +G_BEGIN_DECLS + +#define NM_TYPE_LLDP_LISTENER (nm_lldp_listener_get_type ()) +#define NM_LLDP_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_LLDP_LISTENER, NMLldpListener)) +#define NM_LLDP_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_LLDP_LISTENER, NMLldpListenerClass)) +#define NM_IS_LLDP_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_LLDP_LISTENER)) +#define NM_IS_LLDP_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_LLDP_LISTENER)) +#define NM_LLDP_LISTENER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_LLDP_LISTENER, NMLldpListenerClass)) + +#define NM_LLDP_LISTENER_NEIGHBORS "neighbors" + +struct _NMLldpListener { + GObject parent; +}; + +typedef struct { + GObjectClass parent; +} NMLldpListenerClass; + +GType nm_lldp_listener_get_type (void); +NMLldpListener *nm_lldp_listener_new (void); +gboolean nm_lldp_listener_start (NMLldpListener *self, int ifindex, const char *iface, + const guint8 *mac, guint mac_len, GError **error); +void nm_lldp_listener_stop (NMLldpListener *self); +gboolean nm_lldp_listener_is_running (NMLldpListener *self); + +GVariant *nm_lldp_listener_get_neighbors (NMLldpListener *self); + +G_END_DECLS + +#endif /* __NM_LLDP_LISTENER__ */ diff --git a/src/devices/team/Makefile.am b/src/devices/team/Makefile.am index 46c5fe1d..a6645833 100644 --- a/src/devices/team/Makefile.am +++ b/src/devices/team/Makefile.am @@ -7,32 +7,20 @@ AM_CPPFLAGS = \ -I${top_builddir}/src \ -I${top_srcdir}/src/devices \ -I${top_srcdir}/src/platform \ - -I${top_srcdir}/include \ - -I$(top_builddir)/include \ + -I${top_builddir}/introspection \ + -I${top_srcdir}/shared \ + -I$(top_builddir)/shared \ -I${top_builddir}/libnm-core \ -I${top_srcdir}/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-team"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(DBUS_CFLAGS) + $(GLIB_CFLAGS) if WITH_TEAMDCTL AM_CPPFLAGS += ${LIBTEAMDCTL_CFLAGS} endif -GLIB_GENERATED = nm-team-enum-types.h nm-team-enum-types.c -GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM -GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM -nm_team_enum_types_sources = $(srcdir)/nm-device-team.h - -glue_sources = \ - nm-device-team-glue.h - -%-glue.h: $(top_srcdir)/introspection/%.xml - $(AM_V_GEN) dbus-binding-tool --prefix=$(subst -,_,$(subst -glue.h,,$@)) --mode=glib-server --output=$@ $< - -BUILT_SOURCES = $(GLIB_GENERATED) $(glue_sources) - pkglib_LTLIBRARIES = libnm-device-plugin-team.la SYMBOL_VIS_FILE=$(srcdir)/exports.ver @@ -41,23 +29,21 @@ libnm_device_plugin_team_la_SOURCES = \ nm-device-team.c \ nm-device-team.h \ nm-team-factory.c \ - nm-team-factory.h \ - \ - $(BUILT_SOURCES) + nm-team-factory.h libnm_device_plugin_team_la_LDFLAGS = \ -module -avoid-version \ -Wl,--version-script=$(SYMBOL_VIS_FILE) libnm_device_plugin_team_la_LIBADD = \ - $(DBUS_LIBS) \ + $(top_builddir)/introspection/libnmdbus.la \ + $(GLIB_LIBS) \ $(GUDEV_LIBS) if WITH_TEAMDCTL libnm_device_plugin_team_la_LIBADD += $(LIBTEAMDCTL_LIBS) endif -CLEANFILES = $(BUILT_SOURCES) EXTRA_DIST = $(SYMBOL_VIS_FILE) if ENABLE_TESTS diff --git a/src/devices/team/Makefile.in b/src/devices/team/Makefile.in index 7305b05a..6dce463e 100644 --- a/src/devices/team/Makefile.in +++ b/src/devices/team/Makefile.in @@ -143,13 +143,12 @@ am__installdirs = "$(DESTDIR)$(pkglibdir)" LTLIBRARIES = $(pkglib_LTLIBRARIES) am__DEPENDENCIES_1 = @WITH_TEAMDCTL_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) -libnm_device_plugin_team_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) -am__objects_1 = nm-team-enum-types.lo -am__objects_2 = -am__objects_3 = $(am__objects_1) $(am__objects_2) +libnm_device_plugin_team_la_DEPENDENCIES = \ + $(top_builddir)/introspection/libnmdbus.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_2) am_libnm_device_plugin_team_la_OBJECTS = nm-device-team.lo \ - nm-team-factory.lo $(am__objects_3) + nm-team-factory.lo libnm_device_plugin_team_la_OBJECTS = \ $(am_libnm_device_plugin_team_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) @@ -238,7 +237,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -250,8 +248,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -261,6 +257,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -315,16 +312,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -361,6 +355,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -389,7 +385,6 @@ 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@ @@ -404,6 +399,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -464,6 +461,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -471,6 +469,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -488,40 +487,30 @@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ AM_CPPFLAGS = -I${top_srcdir}/src -I${top_builddir}/src \ -I${top_srcdir}/src/devices -I${top_srcdir}/src/platform \ - -I${top_srcdir}/include -I$(top_builddir)/include \ - -I${top_builddir}/libnm-core -I${top_srcdir}/libnm-core \ + -I${top_builddir}/introspection -I${top_srcdir}/shared \ + -I$(top_builddir)/shared -I${top_builddir}/libnm-core \ + -I${top_srcdir}/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-team"\" \ - -DNETWORKMANAGER_COMPILATION \ - -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE $(DBUS_CFLAGS) \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ + -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE $(GLIB_CFLAGS) \ $(am__append_1) -GLIB_GENERATED = nm-team-enum-types.h nm-team-enum-types.c -GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM -GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM -nm_team_enum_types_sources = $(srcdir)/nm-device-team.h -glue_sources = \ - nm-device-team-glue.h - -BUILT_SOURCES = $(GLIB_GENERATED) $(glue_sources) pkglib_LTLIBRARIES = libnm-device-plugin-team.la SYMBOL_VIS_FILE = $(srcdir)/exports.ver libnm_device_plugin_team_la_SOURCES = \ nm-device-team.c \ nm-device-team.h \ nm-team-factory.c \ - nm-team-factory.h \ - \ - $(BUILT_SOURCES) + nm-team-factory.h libnm_device_plugin_team_la_LDFLAGS = \ -module -avoid-version \ -Wl,--version-script=$(SYMBOL_VIS_FILE) -libnm_device_plugin_team_la_LIBADD = $(DBUS_LIBS) $(GUDEV_LIBS) \ - $(am__append_2) -CLEANFILES = $(BUILT_SOURCES) +libnm_device_plugin_team_la_LIBADD = \ + $(top_builddir)/introspection/libnmdbus.la $(GLIB_LIBS) \ + $(GUDEV_LIBS) $(am__append_2) EXTRA_DIST = $(SYMBOL_VIS_FILE) -all: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) all-am +all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj @@ -600,7 +589,6 @@ distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-device-team.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-team-enum-types.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-team-factory.Plo@am__quote@ .c.o: @@ -715,15 +703,13 @@ distdir: $(DISTFILES) @ENABLE_TESTS_FALSE@check-local: check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-local -check: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) check-am +check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(pkglibdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done -install: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) install-am +install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am @@ -745,7 +731,6 @@ install-strip: mostlyclean-generic: clean-generic: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) @@ -754,7 +739,6 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." - -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-am clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ @@ -826,7 +810,7 @@ ps-am: uninstall-am: uninstall-pkglibLTLIBRARIES -.MAKE: all check check-am install install-am install-strip +.MAKE: check-am install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am check-local clean \ clean-generic clean-libtool clean-pkglibLTLIBRARIES \ @@ -849,9 +833,6 @@ include $(GLIB_MAKEFILE) @GNOME_CODE_COVERAGE_RULES@ -%-glue.h: $(top_srcdir)/introspection/%.xml - $(AM_V_GEN) dbus-binding-tool --prefix=$(subst -,_,$(subst -glue.h,,$@)) --mode=glib-server --output=$@ $< - @ENABLE_TESTS_TRUE@check-local: @ENABLE_TESTS_TRUE@ $(top_srcdir)/tools/check-exports.sh $(builddir)/.libs/libnm-device-plugin-team.so $(SYMBOL_VIS_FILE) diff --git a/src/devices/team/nm-device-team-glue.h b/src/devices/team/nm-device-team-glue.h deleted file mode 100644 index 405975c8..00000000 --- a/src/devices/team/nm-device-team-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_team_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_team_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_team_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_team_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_team_object_info = { 1, - dbus_glib_nm_device_team_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.Team\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.Team\0HwAddress\0hw_address\0read\0org.freedesktop.NetworkManager.Device.Team\0Carrier\0carrier\0read\0org.freedesktop.NetworkManager.Device.Team\0Slaves\0slaves\0read\0\0" -}; - diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index 1950fd2a..c0b83b84 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -24,26 +24,20 @@ #include #include #include -#include -#include -#include #include #include +#include "nm-default.h" #include "nm-device-team.h" -#include "nm-logging.h" #include "NetworkManagerUtils.h" #include "nm-device-private.h" #include "nm-platform.h" -#include "nm-dbus-glib-types.h" -#include "nm-dbus-manager.h" #include "nm-enum-types.h" -#include "nm-team-enum-types.h" #include "nm-core-internal.h" #include "nm-ip4-config.h" -#include "gsystem-local-alloc.h" +#include "nm-dbus-compat.h" -#include "nm-device-team-glue.h" +#include "nmdbus-device-team.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceTeam); @@ -60,13 +54,6 @@ typedef struct { guint teamd_dbus_watch; } NMDeviceTeamPrivate; -enum { - PROP_0, - PROP_SLAVES, - - LAST_PROP -}; - static gboolean teamd_start (NMDevice *device, NMSettingTeam *s_team); /******************************************************************/ @@ -265,15 +252,8 @@ teamd_cleanup (NMDevice *device, gboolean free_tdc) { NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (device); - if (priv->teamd_process_watch) { - g_source_remove (priv->teamd_process_watch); - priv->teamd_process_watch = 0; - } - - if (priv->teamd_timeout) { - g_source_remove (priv->teamd_timeout); - priv->teamd_timeout = 0; - } + nm_clear_g_source (&priv->teamd_process_watch); + nm_clear_g_source (&priv->teamd_timeout); if (priv->teamd_pid > 0) { nm_utils_kill_child_async (priv->teamd_pid, SIGTERM, LOGD_TEAM, "teamd", 2000, NULL, NULL); @@ -333,9 +313,9 @@ teamd_dbus_appeared (GDBusConnection *connection, guint32 pid; ret = g_dbus_connection_call_sync (connection, - "org.freedesktop.DBus", - "/org/freedesktop/DBus", - "org.freedesktop.DBus", + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, "GetConnectionUnixProcessID", g_variant_new ("(s)", name_owner), NULL, @@ -388,7 +368,7 @@ teamd_dbus_vanished (GDBusConnection *dbus_connection, /* Attempt to respawn teamd */ if (state >= NM_DEVICE_STATE_PREPARE && state <= NM_DEVICE_STATE_ACTIVATED) { - NMConnection *connection = nm_device_get_connection (device); + NMConnection *connection = nm_device_get_applied_connection (device); g_assert (connection); if (!teamd_start (device, nm_connection_get_setting_team (connection))) @@ -531,7 +511,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; - connection = nm_device_get_connection (device); + connection = nm_device_get_applied_connection (device); g_assert (connection); s_team = nm_connection_get_setting_team (connection); g_assert (s_team); @@ -572,7 +552,7 @@ ip4_config_pre_commit (NMDevice *self, NMIP4Config *config) NMSettingWired *s_wired; guint32 mtu; - connection = nm_device_get_connection (self); + connection = nm_device_get_applied_connection (self); g_assert (connection); s_wired = nm_connection_get_setting_wired (connection); @@ -650,18 +630,16 @@ enslave_slave (NMDevice *device, } else _LOGI (LOGD_TEAM, "team port %s was enslaved", slave_iface); - g_object_notify (G_OBJECT (device), NM_DEVICE_TEAM_SLAVES); - return TRUE; } -static gboolean +static void release_slave (NMDevice *device, NMDevice *slave, gboolean configure) { NMDeviceTeam *self = NM_DEVICE_TEAM (device); - gboolean success = TRUE, no_firmware = FALSE; + gboolean success, no_firmware = FALSE; if (configure) { success = nm_platform_link_release (NM_PLATFORM_GET, @@ -672,13 +650,7 @@ release_slave (NMDevice *device, _LOGI (LOGD_TEAM, "released team port %s", nm_device_get_ip_iface (slave)); else _LOGW (LOGD_TEAM, "failed to release team port %s", nm_device_get_ip_iface (slave)); - } else - _LOGI (LOGD_TEAM, "team port %s was released", nm_device_get_ip_iface (slave)); - - if (success) - g_object_notify (G_OBJECT (device), NM_DEVICE_TEAM_SLAVES); - if (configure) { /* Kernel team code "closes" the port when releasing it, (which clears * IFF_UP), so we must bring it back up here to ensure carrier changes and * other state is noticed by the now-released port. @@ -686,50 +658,44 @@ release_slave (NMDevice *device, if (!nm_device_bring_up (slave, TRUE, &no_firmware)) _LOGW (LOGD_TEAM, "released team port %s could not be brought up", nm_device_get_ip_iface (slave)); - } - - return success; -} - -/******************************************************************/ - -NMDevice * -nm_device_team_new (NMPlatformLink *platform_device) -{ - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TEAM, - NM_DEVICE_PLATFORM_DEVICE, platform_device, - NM_DEVICE_DRIVER, "team", - NM_DEVICE_TYPE_DESC, "Team", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_TEAM, - NM_DEVICE_IS_MASTER, TRUE, - NULL); + } else + _LOGI (LOGD_TEAM, "team port %s was released", nm_device_get_ip_iface (slave)); } -NMDevice * -nm_device_team_new_for_connection (NMConnection *connection, GError **error) +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + const NMPlatformLink **out_plink, + GError **error) { - const char *iface = nm_connection_get_interface_name (connection); + const char *iface = nm_device_get_iface (device); NMPlatformError plerr; - const NMPlatformLink *plink; - - g_assert (iface); - plerr = nm_platform_team_add (NM_PLATFORM_GET, iface, NULL); + plerr = nm_platform_link_team_add (NM_PLATFORM_GET, iface, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create team master interface '%s' for '%s': %s", iface, nm_connection_get_id (connection), nm_platform_error_to_string (plerr)); - return NULL; + return FALSE; } - plink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, iface); + return TRUE; +} + +/******************************************************************/ + +NMDevice * +nm_device_team_new (const char *iface) +{ return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TEAM, - NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_IFACE, iface, NM_DEVICE_DRIVER, "team", NM_DEVICE_TYPE_DESC, "Team", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_TEAM, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_TEAM, NM_DEVICE_IS_MASTER, TRUE, NULL); } @@ -760,40 +726,6 @@ constructed (GObject *object) g_free (tmp_str); } -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - GPtrArray *slaves; - GSList *list, *iter; - - switch (prop_id) { - break; - case PROP_SLAVES: - slaves = g_ptr_array_new (); - list = nm_device_master_get_slaves (NM_DEVICE (object)); - for (iter = list; iter; iter = iter->next) - g_ptr_array_add (slaves, g_strdup (nm_device_get_path (NM_DEVICE (iter->data)))); - g_slist_free (list); - g_value_take_boxed (value, slaves); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - static void dispose (GObject *object) { @@ -818,14 +750,12 @@ nm_device_team_class_init (NMDeviceTeamClass *klass) g_type_class_add_private (object_class, sizeof (NMDeviceTeamPrivate)); - parent_class->connection_type = NM_SETTING_TEAM_SETTING_NAME; + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_TEAM_SETTING_NAME, NM_LINK_TYPE_TEAM) - /* virtual methods */ object_class->constructed = constructed; - object_class->get_property = get_property; - object_class->set_property = set_property; object_class->dispose = dispose; + parent_class->create_and_realize = create_and_realize; parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->is_available = is_available; parent_class->check_connection_compatible = check_connection_compatible; @@ -840,15 +770,7 @@ nm_device_team_class_init (NMDeviceTeamClass *klass) parent_class->enslave_slave = enslave_slave; parent_class->release_slave = release_slave; - /* properties */ - g_object_class_install_property - (object_class, PROP_SLAVES, - g_param_spec_boxed (NM_DEVICE_TEAM_SLAVES, "", "", - DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_team_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_TEAM_SKELETON, + NULL); } diff --git a/src/devices/team/nm-device-team.h b/src/devices/team/nm-device-team.h index 26ba5737..0e81afa7 100644 --- a/src/devices/team/nm-device-team.h +++ b/src/devices/team/nm-device-team.h @@ -21,8 +21,6 @@ #ifndef __NETWORKMANAGER_DEVICE_TEAM_H__ #define __NETWORKMANAGER_DEVICE_TEAM_H__ -#include - #include "nm-device.h" G_BEGIN_DECLS @@ -34,22 +32,12 @@ G_BEGIN_DECLS #define NM_IS_DEVICE_TEAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_TEAM)) #define NM_DEVICE_TEAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_TEAM, NMDeviceTeamClass)) -#define NM_DEVICE_TEAM_SLAVES "slaves" - -typedef struct { - NMDevice parent; -} NMDeviceTeam; - -typedef struct { - NMDeviceClass parent; - -} NMDeviceTeamClass; - +typedef NMDevice NMDeviceTeam; +typedef NMDeviceClass NMDeviceTeamClass; GType nm_device_team_get_type (void); -NMDevice *nm_device_team_new (NMPlatformLink *platform_device); -NMDevice *nm_device_team_new_for_connection (NMConnection *connection, GError **error); +NMDevice *nm_device_team_new (const char *iface); G_END_DECLS diff --git a/src/devices/team/nm-team-enum-types.c b/src/devices/team/nm-team-enum-types.c deleted file mode 100644 index 5ac3494d..00000000 --- a/src/devices/team/nm-team-enum-types.c +++ /dev/null @@ -1,12 +0,0 @@ - - - -/* Generated by glib-mkenums. Do not edit */ - -#include "nm-team-enum-types.h" - -#include "nm-device-team.h" - - - - diff --git a/src/devices/team/nm-team-enum-types.h b/src/devices/team/nm-team-enum-types.h deleted file mode 100644 index 136cadc2..00000000 --- a/src/devices/team/nm-team-enum-types.h +++ /dev/null @@ -1,17 +0,0 @@ - - - -/* Generated by glib-mkenums. Do not edit */ - -#ifndef __NM_TEAM_ENUM_TYPES_H__ -#define __NM_TEAM_ENUM_TYPES_H__ - -#include - -G_BEGIN_DECLS -G_END_DECLS - -#endif /* __NM_TEAM_ENUM_TYPES_H__ */ - - - diff --git a/src/devices/team/nm-team-factory.c b/src/devices/team/nm-team-factory.c index d87919b6..5f9e142a 100644 --- a/src/devices/team/nm-team-factory.c +++ b/src/devices/team/nm-team-factory.c @@ -26,13 +26,13 @@ #include "nm-device-factory.h" #include "nm-team-factory.h" #include "nm-device-team.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-platform.h" #include "nm-core-internal.h" static GType nm_team_factory_get_type (void); -static void device_factory_interface_init (NMDeviceFactory *factory_iface); +static void device_factory_interface_init (NMDeviceFactoryInterface *factory_iface); G_DEFINE_TYPE_EXTENDED (NMTeamFactory, nm_team_factory, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_FACTORY, device_factory_interface_init)) @@ -48,18 +48,13 @@ nm_device_factory_create (GError **error) /************************************************************************/ static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) { - return nm_device_team_new (plink); -} - -static NMDevice * -create_virtual_device_for_connection (NMDeviceFactory *factory, - NMConnection *connection, - NMDevice *parent, - GError **error) -{ - return nm_device_team_new_for_connection (connection, error); + return nm_device_team_new (iface); } NM_DEVICE_FACTORY_DECLARE_TYPES ( @@ -75,10 +70,9 @@ nm_team_factory_init (NMTeamFactory *self) } static void -device_factory_interface_init (NMDeviceFactory *factory_iface) +device_factory_interface_init (NMDeviceFactoryInterface *factory_iface) { - factory_iface->new_link = new_link; - factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; + factory_iface->create_device = create_device; factory_iface->get_supported_types = get_supported_types; } diff --git a/src/devices/team/nm-team-factory.h b/src/devices/team/nm-team-factory.h index 2f02ac57..9049478d 100644 --- a/src/devices/team/nm-team-factory.h +++ b/src/devices/team/nm-team-factory.h @@ -21,7 +21,7 @@ #ifndef __NETWORKMANAGER_TEAM_FACTORY_H__ #define __NETWORKMANAGER_TEAM_FACTORY_H__ -#include +#include "nm-default.h" #define NM_TYPE_TEAM_FACTORY (nm_team_factory_get_type ()) #define NM_TEAM_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_TEAM_FACTORY, NMTeamFactory)) diff --git a/src/devices/tests/Makefile.am b/src/devices/tests/Makefile.am new file mode 100644 index 00000000..330377b0 --- /dev/null +++ b/src/devices/tests/Makefile.am @@ -0,0 +1,42 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ + -I$(top_srcdir)/libnm-core \ + -I$(top_builddir)/libnm-core \ + -I$(top_srcdir)/src/platform \ + -I$(top_srcdir)/src/devices \ + -I$(top_srcdir)/src/systemd/ \ + -I$(top_srcdir)/src/systemd/src/systemd/ \ + -I$(top_srcdir)/src/systemd/src/libsystemd-network/ \ + -I$(top_srcdir)/src \ + -I$(top_builddir)/src \ + -DG_LOG_DOMAIN=\""NetworkManager"\" \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ + -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ + $(GLIB_CFLAGS) + +AM_CFLAGS = $(CODE_COVERAGE_CFLAGS) +AM_LDFLAGS = $(GLIB_LIBS) $(CODE_COVERAGE_LDFLAGS) +DEVICES_LDADD = \ + $(top_builddir)/src/libNetworkManager.la + +@GNOME_CODE_COVERAGE_RULES@ + +noinst_PROGRAMS = \ + test-lldp + +test_lldp_SOURCES = \ + test-lldp.c \ + ../nm-lldp-listener.c \ + $(top_srcdir)/src/platform/tests/test-common.c + +test_lldp_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir)/src/platform/tests \ + -DSETUP=nm_linux_platform_setup + +test_lldp_LDADD = $(DEVICES_LDADD) + +@VALGRIND_RULES@ +TESTS = \ + test-lldp diff --git a/src/devices/tests/Makefile.in b/src/devices/tests/Makefile.in new file mode 100644 index 00000000..1cfe46b6 --- /dev/null +++ b/src/devices/tests/Makefile.in @@ -0,0 +1,1193 @@ +# Makefile.in generated by automake 1.15 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2014 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 = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +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@ +noinst_PROGRAMS = test-lldp$(EXEEXT) +TESTS = test-lldp$(EXEEXT) +subdir = src/devices/tests +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) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +PROGRAMS = $(noinst_PROGRAMS) +am_test_lldp_OBJECTS = test_lldp-test-lldp.$(OBJEXT) \ + test_lldp-nm-lldp-listener.$(OBJEXT) \ + test_lldp-test-common.$(OBJEXT) +test_lldp_OBJECTS = $(am_test_lldp_OBJECTS) +test_lldp_DEPENDENCIES = $(DEVICES_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_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 = $(test_lldp_SOURCES) +DIST_SOURCES = $(test_lldp_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=''; \ + grn=''; \ + lgn=''; \ + blu=''; \ + mgn=''; \ + brg=''; \ + std=''; \ + fi; \ +} +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__recheck_rx = ^[ ]*:recheck:[ ]* +am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* +am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* +# A command that, given a newline-separated list of test names on the +# standard input, print the name of the tests that are to be re-run +# upon "make recheck". +am__list_recheck_tests = $(AWK) '{ \ + recheck = 1; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + { \ + if ((getline line2 < ($$0 ".log")) < 0) \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ + { \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ + { \ + break; \ + } \ + }; \ + if (recheck) \ + print $$0; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# A command that, given a newline-separated list of test names on the +# standard input, create the global log from their .trs and .log files. +am__create_global_log = $(AWK) ' \ +function fatal(msg) \ +{ \ + print "fatal: making $@: " msg | "cat >&2"; \ + exit 1; \ +} \ +function rst_section(header) \ +{ \ + print header; \ + len = length(header); \ + for (i = 1; i <= len; i = i + 1) \ + printf "="; \ + printf "\n\n"; \ +} \ +{ \ + copy_in_global_log = 1; \ + global_test_result = "RUN"; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".trs"); \ + if (line ~ /$(am__global_test_result_rx)/) \ + { \ + sub("$(am__global_test_result_rx)", "", line); \ + sub("[ ]*$$", "", line); \ + global_test_result = line; \ + } \ + else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ + copy_in_global_log = 0; \ + }; \ + if (copy_in_global_log) \ + { \ + rst_section(global_test_result ": " $$0); \ + while ((rc = (getline line < ($$0 ".log"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".log"); \ + print line; \ + }; \ + printf "\n"; \ + }; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# Restructured Text title. +am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } +# Solaris 10 'make', and several other traditional 'make' implementations, +# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it +# by disabling -e (using the XSI extension "set +e") if it's set. +am__sh_e_setup = case $$- in *e*) set +e;; esac +# Default flags passed to test drivers. +am__common_driver_flags = \ + --color-tests "$$am__color_tests" \ + --enable-hard-errors "$$am__enable_hard_errors" \ + --expect-failure "$$am__expect_failure" +# To be inserted before the command running the test. Creates the +# directory for the log if needed. Stores in $dir the directory +# containing $f, in $tst the test, in $log the log. Executes the +# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and +# passes TESTS_ENVIRONMENT. Set up options for the wrapper that +# will run the test scripts (or their associated LOG_COMPILER, if +# thy have one). +am__check_pre = \ +$(am__sh_e_setup); \ +$(am__vpath_adj_setup) $(am__vpath_adj) \ +$(am__tty_colors); \ +srcdir=$(srcdir); export srcdir; \ +case "$@" in \ + */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ + *) am__odir=.;; \ +esac; \ +test "x$$am__odir" = x"." || test -d "$$am__odir" \ + || $(MKDIR_P) "$$am__odir" || exit $$?; \ +if test -f "./$$f"; then dir=./; \ +elif test -f "$$f"; then dir=; \ +else dir="$(srcdir)/"; fi; \ +tst=$$dir$$f; log='$@'; \ +if test -n '$(DISABLE_HARD_ERRORS)'; then \ + am__enable_hard_errors=no; \ +else \ + am__enable_hard_errors=yes; \ +fi; \ +case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ + am__expect_failure=yes;; \ + *) \ + am__expect_failure=no;; \ +esac; \ +$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) +# A shell command to get the names of the tests scripts with any registered +# extension removed (i.e., equivalently, the names of the test logs, with +# the '.log' extension removed). The result is saved in the shell variable +# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, +# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", +# since that might cause problem with VPATH rewrites for suffix-less tests. +# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. +am__set_TESTS_bases = \ + bases='$(TEST_LOGS)'; \ + bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ + bases=`echo $$bases` +RECHECK_LOGS = $(TEST_LOGS) +AM_RECURSIVE_TARGETS = check recheck +TEST_SUITE_LOG = test-suite.log +TEST_EXTENSIONS = @EXEEXT@ .test +LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) +am__set_b = \ + case '$@' in \ + */*) \ + case '$*' in \ + */*) b='$*';; \ + *) b=`echo '$@' | sed 's/\.log$$//'`; \ + esac;; \ + *) \ + b='$*';; \ + esac +am__test_logs1 = $(TESTS:=.log) +am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) +TEST_LOGS = $(am__test_logs2:.test.log=.log) +TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver +TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ + $(TEST_LOG_FLAGS) +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(top_srcdir)/build-aux/depcomp \ + $(top_srcdir)/build-aux/test-driver +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALL_LINGUAS = @ALL_LINGUAS@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AM_TESTS_FD_REDIRECT = @AM_TESTS_FD_REDIRECT@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BLUEZ5_CFLAGS = @BLUEZ5_CFLAGS@ +BLUEZ5_LIBS = @BLUEZ5_LIBS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +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@ +DBUS_CFLAGS = @DBUS_CFLAGS@ +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@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ +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_CHECK_PATH = @GTKDOC_CHECK_PATH@ +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@ +KERNEL_FIRMWARE_DIR = @KERNEL_FIRMWARE_DIR@ +LCOV = @LCOV@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ +LIBDL = @LIBDL@ +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@ +LOG_DRIVER = @LOG_DRIVER@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +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_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ +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@ +PERL = @PERL@ +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@ +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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ +SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ +SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ +SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ +UDEV_DIR = @UDEV_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@ +nmlibdir = @nmlibdir@ +nmrundir = @nmrundir@ +nmstatedir = @nmstatedir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +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)/shared \ + -I$(top_builddir)/shared \ + -I$(top_srcdir)/libnm-core \ + -I$(top_builddir)/libnm-core \ + -I$(top_srcdir)/src/platform \ + -I$(top_srcdir)/src/devices \ + -I$(top_srcdir)/src/systemd/ \ + -I$(top_srcdir)/src/systemd/src/systemd/ \ + -I$(top_srcdir)/src/systemd/src/libsystemd-network/ \ + -I$(top_srcdir)/src \ + -I$(top_builddir)/src \ + -DG_LOG_DOMAIN=\""NetworkManager"\" \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ + -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ + $(GLIB_CFLAGS) + +AM_CFLAGS = $(CODE_COVERAGE_CFLAGS) +AM_LDFLAGS = $(GLIB_LIBS) $(CODE_COVERAGE_LDFLAGS) +DEVICES_LDADD = \ + $(top_builddir)/src/libNetworkManager.la + +test_lldp_SOURCES = \ + test-lldp.c \ + ../nm-lldp-listener.c \ + $(top_srcdir)/src/platform/tests/test-common.c + +test_lldp_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -I$(top_srcdir)/src/platform/tests \ + -DSETUP=nm_linux_platform_setup + +test_lldp_LDADD = $(DEVICES_LDADD) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/devices/tests/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 + +test-lldp$(EXEEXT): $(test_lldp_OBJECTS) $(test_lldp_DEPENDENCIES) $(EXTRA_test_lldp_DEPENDENCIES) + @rm -f test-lldp$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_lldp_OBJECTS) $(test_lldp_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lldp-nm-lldp-listener.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lldp-test-common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_lldp-test-lldp.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 -o $@ $< + +.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 -o $@ `$(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 $@ $< + +test_lldp-test-lldp.o: test-lldp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lldp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lldp-test-lldp.o -MD -MP -MF $(DEPDIR)/test_lldp-test-lldp.Tpo -c -o test_lldp-test-lldp.o `test -f 'test-lldp.c' || echo '$(srcdir)/'`test-lldp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lldp-test-lldp.Tpo $(DEPDIR)/test_lldp-test-lldp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-lldp.c' object='test_lldp-test-lldp.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_lldp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lldp-test-lldp.o `test -f 'test-lldp.c' || echo '$(srcdir)/'`test-lldp.c + +test_lldp-test-lldp.obj: test-lldp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lldp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lldp-test-lldp.obj -MD -MP -MF $(DEPDIR)/test_lldp-test-lldp.Tpo -c -o test_lldp-test-lldp.obj `if test -f 'test-lldp.c'; then $(CYGPATH_W) 'test-lldp.c'; else $(CYGPATH_W) '$(srcdir)/test-lldp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lldp-test-lldp.Tpo $(DEPDIR)/test_lldp-test-lldp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-lldp.c' object='test_lldp-test-lldp.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_lldp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lldp-test-lldp.obj `if test -f 'test-lldp.c'; then $(CYGPATH_W) 'test-lldp.c'; else $(CYGPATH_W) '$(srcdir)/test-lldp.c'; fi` + +test_lldp-nm-lldp-listener.o: ../nm-lldp-listener.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lldp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lldp-nm-lldp-listener.o -MD -MP -MF $(DEPDIR)/test_lldp-nm-lldp-listener.Tpo -c -o test_lldp-nm-lldp-listener.o `test -f '../nm-lldp-listener.c' || echo '$(srcdir)/'`../nm-lldp-listener.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lldp-nm-lldp-listener.Tpo $(DEPDIR)/test_lldp-nm-lldp-listener.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-lldp-listener.c' object='test_lldp-nm-lldp-listener.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_lldp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lldp-nm-lldp-listener.o `test -f '../nm-lldp-listener.c' || echo '$(srcdir)/'`../nm-lldp-listener.c + +test_lldp-nm-lldp-listener.obj: ../nm-lldp-listener.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lldp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lldp-nm-lldp-listener.obj -MD -MP -MF $(DEPDIR)/test_lldp-nm-lldp-listener.Tpo -c -o test_lldp-nm-lldp-listener.obj `if test -f '../nm-lldp-listener.c'; then $(CYGPATH_W) '../nm-lldp-listener.c'; else $(CYGPATH_W) '$(srcdir)/../nm-lldp-listener.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lldp-nm-lldp-listener.Tpo $(DEPDIR)/test_lldp-nm-lldp-listener.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='../nm-lldp-listener.c' object='test_lldp-nm-lldp-listener.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_lldp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lldp-nm-lldp-listener.obj `if test -f '../nm-lldp-listener.c'; then $(CYGPATH_W) '../nm-lldp-listener.c'; else $(CYGPATH_W) '$(srcdir)/../nm-lldp-listener.c'; fi` + +test_lldp-test-common.o: $(top_srcdir)/src/platform/tests/test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lldp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lldp-test-common.o -MD -MP -MF $(DEPDIR)/test_lldp-test-common.Tpo -c -o test_lldp-test-common.o `test -f '$(top_srcdir)/src/platform/tests/test-common.c' || echo '$(srcdir)/'`$(top_srcdir)/src/platform/tests/test-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lldp-test-common.Tpo $(DEPDIR)/test_lldp-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/src/platform/tests/test-common.c' object='test_lldp-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_lldp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lldp-test-common.o `test -f '$(top_srcdir)/src/platform/tests/test-common.c' || echo '$(srcdir)/'`$(top_srcdir)/src/platform/tests/test-common.c + +test_lldp-test-common.obj: $(top_srcdir)/src/platform/tests/test-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_lldp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_lldp-test-common.obj -MD -MP -MF $(DEPDIR)/test_lldp-test-common.Tpo -c -o test_lldp-test-common.obj `if test -f '$(top_srcdir)/src/platform/tests/test-common.c'; then $(CYGPATH_W) '$(top_srcdir)/src/platform/tests/test-common.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/src/platform/tests/test-common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_lldp-test-common.Tpo $(DEPDIR)/test_lldp-test-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$(top_srcdir)/src/platform/tests/test-common.c' object='test_lldp-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_lldp_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_lldp-test-common.obj `if test -f '$(top_srcdir)/src/platform/tests/test-common.c'; then $(CYGPATH_W) '$(top_srcdir)/src/platform/tests/test-common.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/src/platform/tests/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 + +# Recover from deleted '.trs' file; this should ensure that +# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create +# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells +# to avoid problems with "make -n". +.log.trs: + rm -f $< $@ + $(MAKE) $(AM_MAKEFLAGS) $< + +# Leading 'am--fnord' is there to ensure the list of targets does not +# expand to empty, as could happen e.g. with make check TESTS=''. +am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) +am--force-recheck: + @: + +$(TEST_SUITE_LOG): $(TEST_LOGS) + @$(am__set_TESTS_bases); \ + am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ + redo_bases=`for i in $$bases; do \ + am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ + done`; \ + if test -n "$$redo_bases"; then \ + redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ + redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ + if $(am__make_dryrun); then :; else \ + rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ + fi; \ + fi; \ + if test -n "$$am__remaking_logs"; then \ + echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ + "recursion detected" >&2; \ + elif test -n "$$redo_logs"; then \ + am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ + fi; \ + if $(am__make_dryrun); then :; else \ + st=0; \ + errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ + for i in $$redo_bases; do \ + test -f $$i.trs && test -r $$i.trs \ + || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ + test -f $$i.log && test -r $$i.log \ + || { echo "$$errmsg $$i.log" >&2; st=1; }; \ + done; \ + test $$st -eq 0 || exit 1; \ + fi + @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ + ws='[ ]'; \ + results=`for b in $$bases; do echo $$b.trs; done`; \ + test -n "$$results" || results=/dev/null; \ + all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ + pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ + fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ + skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ + xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ + xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ + error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ + if test `expr $$fail + $$xpass + $$error` -eq 0; then \ + success=true; \ + else \ + success=false; \ + fi; \ + br='==================='; br=$$br$$br$$br$$br; \ + result_count () \ + { \ + if test x"$$1" = x"--maybe-color"; then \ + maybe_colorize=yes; \ + elif test x"$$1" = x"--no-color"; then \ + maybe_colorize=no; \ + else \ + echo "$@: invalid 'result_count' usage" >&2; exit 4; \ + fi; \ + shift; \ + desc=$$1 count=$$2; \ + if test $$maybe_colorize = yes && test $$count -gt 0; then \ + color_start=$$3 color_end=$$std; \ + else \ + color_start= color_end=; \ + fi; \ + echo "$${color_start}# $$desc $$count$${color_end}"; \ + }; \ + create_testsuite_report () \ + { \ + result_count $$1 "TOTAL:" $$all "$$brg"; \ + result_count $$1 "PASS: " $$pass "$$grn"; \ + result_count $$1 "SKIP: " $$skip "$$blu"; \ + result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ + result_count $$1 "FAIL: " $$fail "$$red"; \ + result_count $$1 "XPASS:" $$xpass "$$red"; \ + result_count $$1 "ERROR:" $$error "$$mgn"; \ + }; \ + { \ + echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ + $(am__rst_title); \ + create_testsuite_report --no-color; \ + echo; \ + echo ".. contents:: :depth: 2"; \ + echo; \ + for b in $$bases; do echo $$b; done \ + | $(am__create_global_log); \ + } >$(TEST_SUITE_LOG).tmp || exit 1; \ + mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ + if $$success; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ + fi; \ + echo "$${col}$$br$${std}"; \ + echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ + echo "$${col}$$br$${std}"; \ + create_testsuite_report --maybe-color; \ + echo "$$col$$br$$std"; \ + if $$success; then :; else \ + echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ + if test -n "$(PACKAGE_BUGREPORT)"; then \ + echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ + fi; \ + echo "$$col$$br$$std"; \ + fi; \ + $$success || exit 1 + +check-TESTS: + @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list + @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + trs_list=`for i in $$bases; do echo $$i.trs; done`; \ + log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ + exit $$?; +recheck: all + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + bases=`for i in $$bases; do echo $$i; done \ + | $(am__list_recheck_tests)` || exit 1; \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + log_list=`echo $$log_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ + am__force_recheck=am--force-recheck \ + TEST_LOGS="$$log_list"; \ + exit $$? +test-lldp.log: test-lldp$(EXEEXT) + @p='test-lldp$(EXEEXT)'; \ + b='test-lldp'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +.test.log: + @p='$<'; \ + $(am__set_b); \ + $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +@am__EXEEXT_TRUE@.test$(EXEEXT).log: +@am__EXEEXT_TRUE@ @p='$<'; \ +@am__EXEEXT_TRUE@ $(am__set_b); \ +@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ +@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ +@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ +@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) + +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: + -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) + -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) + -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + +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 \ + recheck tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +@GNOME_CODE_COVERAGE_RULES@ + +@VALGRIND_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/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c new file mode 100644 index 00000000..c339d9ca --- /dev/null +++ b/src/devices/tests/test-lldp.c @@ -0,0 +1,221 @@ +/* -*- 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) 2015 Red Hat, Inc. + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "nm-default.h" +#include "nm-lldp-listener.h" +#include "test-common.h" + +typedef struct { + int ifindex; + int fd; + guint8 mac[ETH_ALEN]; +} test_fixture; + +#define TEST_IFNAME "nm-tap-test0" + +static void +fixture_setup (test_fixture *fixture, gconstpointer user_data) +{ + const NMPlatformLink *link; + struct ifreq ifr = { }; + int fd, s; + + fd = open ("/dev/net/tun", O_RDWR); + g_assert (fd >= 0); + + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + strncpy (ifr.ifr_name, TEST_IFNAME, IFNAMSIZ); + g_assert (ioctl (fd, TUNSETIFF, &ifr) >= 0); + + /* Bring the interface up */ + s = socket (AF_INET, SOCK_DGRAM, 0); + g_assert (s >= 0); + ifr.ifr_flags |= IFF_UP; + g_assert (ioctl (s, SIOCSIFFLAGS, &ifr) >= 0); + close (s); + + nm_platform_process_events (NM_PLATFORM_GET); + link = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, TEST_IFNAME); + g_assert (link); + fixture->ifindex = link->ifindex; + fixture->fd = fd; + memcpy (fixture->mac, link->addr.data, ETH_ALEN); +} + +typedef struct { + int num_called; +} TestInfo; + +static gboolean +loop_quit (gpointer user_data) +{ + g_main_loop_quit ((GMainLoop *) user_data); + return G_SOURCE_REMOVE; +} + +static void +lldp_neighbors_changed (NMLldpListener *lldp_listener, GParamSpec *pspec, + gpointer user_data) +{ + TestInfo *info = user_data; + + info->num_called++; +} + +static GVariant * +get_lldp_neighbor_attribute (GVariant *neighbors, + const char *chassis, const char *port, + const char *name) +{ + GVariantIter iter, attrs_iter; + GVariant *variant, *attr_variant; + const char *attr_name; + GVariant *chassis_v, *port_v, *attr_v; + + g_return_val_if_fail (g_variant_is_of_type (neighbors, + G_VARIANT_TYPE ("aa{sv}")), + NULL); + g_variant_iter_init (&iter, neighbors); + + while (g_variant_iter_next (&iter, "@a{sv}", &variant)) { + g_variant_iter_init (&attrs_iter, variant); + chassis_v = NULL; + port_v = NULL; + attr_v = NULL; + + while (g_variant_iter_next (&attrs_iter, "{&sv}", &attr_name, &attr_variant)) { + if (!g_strcmp0 (attr_name, NM_LLDP_ATTR_CHASSIS_ID)) + chassis_v = attr_variant; + else if (!g_strcmp0 (attr_name, NM_LLDP_ATTR_PORT_ID)) + port_v = attr_variant; + else if (!g_strcmp0 (attr_name, name)) + attr_v = attr_variant; + } + + if ( g_variant_is_of_type (chassis_v, G_VARIANT_TYPE_STRING) + && g_variant_is_of_type (port_v, G_VARIANT_TYPE_STRING) + && !g_strcmp0 (chassis, g_variant_get_string (chassis_v, NULL)) + && !g_strcmp0 (port, g_variant_get_string (port_v, NULL))) { + + g_variant_ref (attr_v); + g_variant_unref (variant); + + return attr_v; + } + g_variant_unref (variant); + } + + /* neighbor not found */ + return NULL; +} + +static void +test_receive_frame (test_fixture *fixture, gconstpointer user_data) +{ + NMLldpListener *listener; + GMainLoop *loop; + TestInfo info = { }; + GVariant *neighbors, *attr; + uint8_t frame[] = { + /* Ethernet header */ + 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC */ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */ + 0x88, 0xcc, /* Ethertype */ + /* LLDP mandatory TLVs */ + 0x02, 0x07, 0x04, 0x00, 0x01, 0x02, /* Chassis: MAC, 00:01:02:03:04:05 */ + 0x03, 0x04, 0x05, + 0x04, 0x04, 0x05, 0x31, 0x2f, 0x33, /* Port: interface name, "1/3" */ + 0x06, 0x02, 0x00, 0x78, /* TTL: 120 seconds */ + /* LLDP optional TLVs */ + 0x08, 0x04, 0x50, 0x6f, 0x72, 0x74, /* Port Description: "Port" */ + 0x0a, 0x03, 0x53, 0x59, 0x53, /* System Name: "SYS" */ + 0x0c, 0x04, 0x66, 0x6f, 0x6f, 0x00, /* System Description: "foo" (NULL-terminated) */ + 0x00, 0x00 /* End Of LLDPDU */ + }; + + listener = nm_lldp_listener_new (); + g_assert (listener != NULL); + g_assert (nm_lldp_listener_start (listener, fixture->ifindex, TEST_IFNAME, fixture->mac, ETH_ALEN, NULL)); + + g_signal_connect (listener, "notify::" NM_LLDP_LISTENER_NEIGHBORS, + (GCallback) lldp_neighbors_changed, &info); + loop = g_main_loop_new (NULL, FALSE); + g_timeout_add_seconds (1, loop_quit, loop); + + g_assert (write (fixture->fd, frame, sizeof (frame)) == sizeof (frame)); + g_assert (write (fixture->fd, frame, sizeof (frame)) == sizeof (frame)); + + g_main_loop_run (loop); + + g_assert_cmpint (info.num_called, ==, 1); + neighbors = nm_lldp_listener_get_neighbors (listener); + g_assert (neighbors != NULL); + + /* Check port description */ + attr = get_lldp_neighbor_attribute (neighbors, "00:01:02:03:04:05", "1/3", + NM_LLDP_ATTR_PORT_DESCRIPTION); + g_assert (attr != NULL); + g_assert (g_variant_is_of_type (attr, G_VARIANT_TYPE_STRING)); + g_assert_cmpstr (g_variant_get_string (attr, NULL), ==, "Port"); + + /* Check system name */ + attr = get_lldp_neighbor_attribute (neighbors, "00:01:02:03:04:05", "1/3", + NM_LLDP_ATTR_SYSTEM_NAME); + g_assert (attr != NULL); + g_assert (g_variant_is_of_type (attr, G_VARIANT_TYPE_STRING)); + g_assert_cmpstr (g_variant_get_string (attr, NULL), ==, "SYS"); + + /* Check destination */ + attr = get_lldp_neighbor_attribute (neighbors, "00:01:02:03:04:05", "1/3", + NM_LLDP_ATTR_DESTINATION); + g_assert (attr != NULL); + g_assert (g_variant_is_of_type (attr, G_VARIANT_TYPE_STRING)); + g_assert_cmpstr (g_variant_get_string (attr, NULL), ==, + NM_LLDP_DEST_NEAREST_NON_TPMR_BRIDGE); + + g_clear_pointer (&loop, g_main_loop_unref); +} + +static void +fixture_teardown (test_fixture *fixture, gconstpointer user_data) +{ + nm_platform_link_delete (NM_PLATFORM_GET, fixture->ifindex); +} + +void +init_tests (int *argc, char ***argv) +{ + nmtst_init_assert_logging (argc, argv, "WARN", "ALL"); +} + +void +setup_tests (void) +{ + g_test_add ("/lldp/receive_frame", test_fixture, NULL, fixture_setup, + test_receive_frame, fixture_teardown); +} diff --git a/src/devices/wifi/Makefile.am b/src/devices/wifi/Makefile.am index 4ac59e3d..b0919ef7 100644 --- a/src/devices/wifi/Makefile.am +++ b/src/devices/wifi/Makefile.am @@ -2,7 +2,9 @@ include $(GLIB_MAKEFILE) @GNOME_CODE_COVERAGE_RULES@ +if ENABLE_TESTS SUBDIRS=. tests +endif AM_CPPFLAGS = \ -I${top_srcdir}/src \ @@ -11,31 +13,15 @@ AM_CPPFLAGS = \ -I${top_srcdir}/src/settings \ -I${top_srcdir}/src/platform \ -I${top_srcdir}/src/supplicant-manager \ - -I${top_srcdir}/include \ - -I$(top_builddir)/include \ + -I${top_builddir}/introspection \ + -I${top_srcdir}/shared \ + -I$(top_builddir)/shared \ -I${top_builddir}/libnm-core \ -I${top_srcdir}/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-wifi"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(DBUS_CFLAGS) - -GLIB_GENERATED = nm-wifi-enum-types.h nm-wifi-enum-types.c -GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM -GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM -nm_wifi_enum_types_sources = \ - $(srcdir)/nm-device-wifi.h \ - $(srcdir)/nm-wifi-ap.h \ - $(srcdir)/nm-device-olpc-mesh.h - -glue_sources = \ - nm-device-wifi-glue.h \ - nm-device-olpc-mesh-glue.h - -%-glue.h: $(top_srcdir)/introspection/%.xml - $(AM_V_GEN) dbus-binding-tool --prefix=$(subst -,_,$(subst -glue.h,,$@)) --mode=glib-server --output=$@ $< - -BUILT_SOURCES = $(GLIB_GENERATED) $(glue_sources) + $(GLIB_CFLAGS) pkglib_LTLIBRARIES = libnm-device-plugin-wifi.la @@ -48,9 +34,7 @@ libnm_device_plugin_wifi_la_SOURCES = \ nm-wifi-ap-utils.c \ nm-wifi-ap-utils.h \ nm-device-olpc-mesh.c \ - nm-device-olpc-mesh.h \ - \ - $(BUILT_SOURCES) + nm-device-olpc-mesh.h SYMBOL_VIS_FILE=$(srcdir)/exports.ver @@ -59,11 +43,10 @@ libnm_device_plugin_wifi_la_LDFLAGS = \ -Wl,--version-script=$(SYMBOL_VIS_FILE) libnm_device_plugin_wifi_la_LIBADD = \ - $(DBUS_LIBS) \ + $(top_builddir)/introspection/libnmdbus.la \ + $(GLIB_LIBS) \ $(GUDEV_LIBS) -CLEANFILES = $(BUILT_SOURCES) - EXTRA_DIST = $(SYMBOL_VIS_FILE) if ENABLE_TESTS diff --git a/src/devices/wifi/Makefile.in b/src/devices/wifi/Makefile.in index 82ebad74..1286a480 100644 --- a/src/devices/wifi/Makefile.in +++ b/src/devices/wifi/Makefile.in @@ -140,14 +140,12 @@ am__uninstall_files_from_dir = { \ am__installdirs = "$(DESTDIR)$(pkglibdir)" LTLIBRARIES = $(pkglib_LTLIBRARIES) am__DEPENDENCIES_1 = -libnm_device_plugin_wifi_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -am__objects_1 = nm-wifi-enum-types.lo -am__objects_2 = -am__objects_3 = $(am__objects_1) $(am__objects_2) +libnm_device_plugin_wifi_la_DEPENDENCIES = \ + $(top_builddir)/introspection/libnmdbus.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am_libnm_device_plugin_wifi_la_OBJECTS = nm-wifi-factory.lo \ nm-device-wifi.lo nm-wifi-ap.lo nm-wifi-ap-utils.lo \ - nm-device-olpc-mesh.lo $(am__objects_3) + nm-device-olpc-mesh.lo libnm_device_plugin_wifi_la_OBJECTS = \ $(am_libnm_device_plugin_wifi_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) @@ -234,7 +232,7 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags -DIST_SUBDIRS = $(SUBDIRS) +DIST_SUBDIRS = . tests am__DIST_COMMON = $(srcdir)/Makefile.in \ $(top_srcdir)/build-aux/depcomp DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) @@ -278,7 +276,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -290,8 +287,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -301,6 +296,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -355,16 +351,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -401,6 +394,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -429,7 +424,6 @@ 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@ @@ -444,6 +438,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -504,6 +500,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -511,6 +508,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -526,7 +524,7 @@ with_dhcpcd = @with_dhcpcd@ with_netconfig = @with_netconfig@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ -SUBDIRS = . tests +@ENABLE_TESTS_TRUE@SUBDIRS = . tests AM_CPPFLAGS = \ -I${top_srcdir}/src \ -I${top_builddir}/src \ @@ -534,28 +532,16 @@ AM_CPPFLAGS = \ -I${top_srcdir}/src/settings \ -I${top_srcdir}/src/platform \ -I${top_srcdir}/src/supplicant-manager \ - -I${top_srcdir}/include \ - -I$(top_builddir)/include \ + -I${top_builddir}/introspection \ + -I${top_srcdir}/shared \ + -I$(top_builddir)/shared \ -I${top_builddir}/libnm-core \ -I${top_srcdir}/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-wifi"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(DBUS_CFLAGS) + $(GLIB_CFLAGS) -GLIB_GENERATED = nm-wifi-enum-types.h nm-wifi-enum-types.c -GLIB_MKENUMS_H_FLAGS = --identifier-prefix NM -GLIB_MKENUMS_C_FLAGS = --identifier-prefix NM -nm_wifi_enum_types_sources = \ - $(srcdir)/nm-device-wifi.h \ - $(srcdir)/nm-wifi-ap.h \ - $(srcdir)/nm-device-olpc-mesh.h - -glue_sources = \ - nm-device-wifi-glue.h \ - nm-device-olpc-mesh-glue.h - -BUILT_SOURCES = $(GLIB_GENERATED) $(glue_sources) pkglib_LTLIBRARIES = libnm-device-plugin-wifi.la libnm_device_plugin_wifi_la_SOURCES = \ nm-wifi-factory.c \ @@ -566,9 +552,7 @@ libnm_device_plugin_wifi_la_SOURCES = \ nm-wifi-ap-utils.c \ nm-wifi-ap-utils.h \ nm-device-olpc-mesh.c \ - nm-device-olpc-mesh.h \ - \ - $(BUILT_SOURCES) + nm-device-olpc-mesh.h SYMBOL_VIS_FILE = $(srcdir)/exports.ver libnm_device_plugin_wifi_la_LDFLAGS = \ @@ -576,13 +560,12 @@ libnm_device_plugin_wifi_la_LDFLAGS = \ -Wl,--version-script=$(SYMBOL_VIS_FILE) libnm_device_plugin_wifi_la_LIBADD = \ - $(DBUS_LIBS) \ + $(top_builddir)/introspection/libnmdbus.la \ + $(GLIB_LIBS) \ $(GUDEV_LIBS) -CLEANFILES = $(BUILT_SOURCES) EXTRA_DIST = $(SYMBOL_VIS_FILE) -all: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) all-recursive +all: all-recursive .SUFFIXES: .SUFFIXES: .c .lo .o .obj @@ -664,7 +647,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-device-wifi.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-wifi-ap-utils.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-wifi-ap.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-wifi-enum-types.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-wifi-factory.Plo@am__quote@ .c.o: @@ -851,16 +833,14 @@ distdir: $(DISTFILES) @ENABLE_TESTS_FALSE@check-local: check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-local -check: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) check-recursive +check: check-recursive all-am: Makefile $(LTLIBRARIES) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(pkglibdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done -install: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) install-recursive +install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive @@ -882,7 +862,6 @@ install-strip: mostlyclean-generic: clean-generic: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) @@ -891,7 +870,6 @@ distclean-generic: maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." - -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) clean: clean-recursive clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ @@ -963,8 +941,7 @@ ps-am: uninstall-am: uninstall-pkglibLTLIBRARIES -.MAKE: $(am__recursive_targets) all check check-am install install-am \ - install-strip +.MAKE: $(am__recursive_targets) check-am install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am check-local clean clean-generic clean-libtool \ @@ -988,9 +965,6 @@ include $(GLIB_MAKEFILE) @GNOME_CODE_COVERAGE_RULES@ -%-glue.h: $(top_srcdir)/introspection/%.xml - $(AM_V_GEN) dbus-binding-tool --prefix=$(subst -,_,$(subst -glue.h,,$@)) --mode=glib-server --output=$@ $< - @ENABLE_TESTS_TRUE@check-local: @ENABLE_TESTS_TRUE@ $(top_srcdir)/tools/check-exports.sh $(builddir)/.libs/libnm-device-plugin-wifi.so $(SYMBOL_VIS_FILE) diff --git a/src/devices/wifi/nm-device-olpc-mesh-glue.h b/src/devices/wifi/nm-device-olpc-mesh-glue.h deleted file mode 100644 index 04b5e83f..00000000 --- a/src/devices/wifi/nm-device-olpc-mesh-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_olpc_mesh_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_olpc_mesh_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_olpc_mesh_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_olpc_mesh_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_olpc_mesh_object_info = { 1, - dbus_glib_nm_device_olpc_mesh_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.OlpcMesh\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.OlpcMesh\0HwAddress\0hw_address\0read\0org.freedesktop.NetworkManager.Device.OlpcMesh\0Companion\0companion\0read\0org.freedesktop.NetworkManager.Device.OlpcMesh\0ActiveChannel\0active_channel\0read\0\0" -}; - diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c index e67d1a20..23ebd9c8 100644 --- a/src/devices/wifi/nm-device-olpc-mesh.c +++ b/src/devices/wifi/nm-device-olpc-mesh.c @@ -26,9 +26,6 @@ #include "config.h" -#include -#include -#include #include #include #include @@ -38,27 +35,24 @@ #include #include +#include "nm-default.h" #include "nm-device.h" #include "nm-device-wifi.h" #include "nm-device-olpc-mesh.h" #include "nm-device-private.h" #include "nm-utils.h" -#include "nm-logging.h" #include "NetworkManagerUtils.h" #include "nm-activation-request.h" #include "nm-setting-connection.h" #include "nm-setting-olpc-mesh.h" #include "nm-manager.h" #include "nm-enum-types.h" -#include "nm-dbus-manager.h" #include "nm-platform.h" -#include "nm-wifi-enum-types.h" /* This is a bug; but we can't really change API now... */ #include "nm-vpn-dbus-interface.h" - -#include "nm-device-olpc-mesh-glue.h" +#include "nmdbus-device-olpc-mesh.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceOlpcMesh); @@ -77,6 +71,7 @@ enum { struct _NMDeviceOlpcMeshPrivate { NMDevice *companion; + NMManager *manager; gboolean stage1_waiting; }; @@ -213,7 +208,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) GBytes *ssid; const char *anycast_addr; - connection = nm_device_get_connection (device); + connection = nm_device_get_applied_connection (device); g_assert (connection); s_mesh = nm_connection_get_setting_olpc_mesh (connection); @@ -345,7 +340,7 @@ check_companion (NMDeviceOlpcMesh *self, NMDevice *other) _LOGI (LOGD_OLPC, "found companion WiFi device %s", nm_device_get_iface (other)); - g_signal_connect (G_OBJECT (other), "state-changed", + g_signal_connect (G_OBJECT (other), NM_DEVICE_STATE_CHANGED, G_CALLBACK (companion_state_changed_cb), self); g_signal_connect (G_OBJECT (other), "notify::scanning", @@ -397,7 +392,7 @@ find_companion (NMDeviceOlpcMesh *self) nm_device_add_pending_action (NM_DEVICE (self), "waiting for companion", TRUE); /* Try to find the companion if it's already known to the NMManager */ - for (list = nm_manager_get_devices (nm_manager_get ()); list ; list = g_slist_next (list)) { + for (list = nm_manager_get_devices (priv->manager); list ; list = g_slist_next (list)) { if (check_companion (self, NM_DEVICE (list->data))) { nm_device_queue_recheck_available (NM_DEVICE (self), NM_DEVICE_STATE_REASON_NONE, @@ -421,14 +416,13 @@ state_changed (NMDevice *device, /*******************************************************************/ NMDevice * -nm_device_olpc_mesh_new (NMPlatformLink *platform_device) +nm_device_olpc_mesh_new (const char *iface) { - g_return_val_if_fail (platform_device != NULL, NULL); - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_OLPC_MESH, - NM_DEVICE_PLATFORM_DEVICE, platform_device, + NM_DEVICE_IFACE, iface, NM_DEVICE_TYPE_DESC, "802.11 OLPC Mesh", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_OLPC_MESH, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_OLPC_MESH, NULL); } @@ -437,35 +431,21 @@ nm_device_olpc_mesh_init (NMDeviceOlpcMesh * self) { } -static GObject* -constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) +static void +constructed (GObject *object) { - GObject *object; - GObjectClass *klass; - NMDeviceOlpcMesh *self; - NMDeviceWifiCapabilities caps; - - klass = G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class); - object = klass->constructor (type, n_construct_params, construct_params); - if (!object) - return NULL; - - self = NM_DEVICE_OLPC_MESH (object); - - if (!nm_platform_wifi_get_capabilities (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (self)), &caps)) { - _LOGW (LOGD_HW | LOGD_OLPC, "failed to initialize WiFi driver"); - g_object_unref (object); - return NULL; - } + NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (object); + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); - g_signal_connect (nm_manager_get (), "device-added", G_CALLBACK (device_added_cb), self); - g_signal_connect (nm_manager_get (), "device-removed", G_CALLBACK (device_removed_cb), self); + G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->constructed (object); + + priv->manager = g_object_ref (nm_manager_get ()); + + g_signal_connect (priv->manager, "device-added", G_CALLBACK (device_added_cb), self); + g_signal_connect (priv->manager, "device-removed", G_CALLBACK (device_removed_cb), self); /* shorter timeout for mesh connectivity */ nm_device_set_dhcp_timeout (NM_DEVICE (self), 20); - return object; } static void @@ -477,10 +457,7 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_COMPANION: - if (priv->companion) - g_value_set_boxed (value, nm_device_get_path (priv->companion)); - else - g_value_set_boxed (value, "/"); + nm_utils_g_value_set_object_path (value, priv->companion); break; case PROP_ACTIVE_CHANNEL: g_value_set_uint (value, nm_platform_mesh_get_channel (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (device)))); @@ -506,10 +483,15 @@ static void dispose (GObject *object) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (object); + NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); companion_cleanup (self); - g_signal_handlers_disconnect_by_func (nm_manager_get (), G_CALLBACK (device_added_cb), self); - g_signal_handlers_disconnect_by_func (nm_manager_get (), G_CALLBACK (device_removed_cb), self); + + if (priv->manager) { + g_signal_handlers_disconnect_by_func (priv->manager, G_CALLBACK (device_added_cb), self); + g_signal_handlers_disconnect_by_func (priv->manager, G_CALLBACK (device_removed_cb), self); + g_clear_object (&priv->manager); + } G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object); } @@ -522,7 +504,9 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) g_type_class_add_private (object_class, sizeof (NMDeviceOlpcMeshPrivate)); - object_class->constructor = constructor; + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_OLPC_MESH_SETTING_NAME, NM_LINK_TYPE_OLPC_MESH) + + object_class->constructed = constructed; object_class->get_property = get_property; object_class->set_property = set_property; object_class->dispose = dispose; @@ -540,10 +524,10 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) /* Properties */ g_object_class_install_property (object_class, PROP_COMPANION, - g_param_spec_boxed (NM_DEVICE_OLPC_MESH_COMPANION, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_DEVICE_OLPC_MESH_COMPANION, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_ACTIVE_CHANNEL, @@ -552,8 +536,8 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_olpc_mesh_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_OLPC_MESH_SKELETON, + NULL); } diff --git a/src/devices/wifi/nm-device-olpc-mesh.h b/src/devices/wifi/nm-device-olpc-mesh.h index 67d83fb0..63895a88 100644 --- a/src/devices/wifi/nm-device-olpc-mesh.h +++ b/src/devices/wifi/nm-device-olpc-mesh.h @@ -28,8 +28,6 @@ #ifndef __NETWORKMANAGER_DEVICE_OLPC_MESH_H__ #define __NETWORKMANAGER_DEVICE_OLPC_MESH_H__ -#include - #include "nm-device.h" G_BEGIN_DECLS @@ -67,7 +65,7 @@ struct _NMDeviceOlpcMeshClass GType nm_device_olpc_mesh_get_type (void); -NMDevice *nm_device_olpc_mesh_new (NMPlatformLink *platform_device); +NMDevice *nm_device_olpc_mesh_new (const char *iface); G_END_DECLS diff --git a/src/devices/wifi/nm-device-wifi-glue.h b/src/devices/wifi/nm-device-wifi-glue.h deleted file mode 100644 index 8f8da2af..00000000 --- a/src/devices/wifi/nm-device-wifi-glue.h +++ /dev/null @@ -1,167 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_wifi_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_wifi_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -/* BOOLEAN:POINTER,POINTER */ -extern void dbus_glib_marshal_nm_device_wifi_BOOLEAN__POINTER_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_device_wifi_BOOLEAN__POINTER_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer data2); - GMarshalFunc_BOOLEAN__POINTER_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - gboolean v_return; - - g_return_if_fail (return_value != NULL); - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_BOOLEAN__POINTER_POINTER) (marshal_data ? marshal_data : cc->callback); - - v_return = callback (data1, - g_marshal_value_peek_pointer (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - data2); - - g_value_set_boolean (return_value, v_return); -} - -/* NONE:BOXED,POINTER */ -extern void dbus_glib_marshal_nm_device_wifi_VOID__BOXED_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_device_wifi_VOID__BOXED_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__BOXED_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer data2); - GMarshalFunc_VOID__BOXED_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_VOID__BOXED_POINTER) (marshal_data ? marshal_data : cc->callback); - - callback (data1, - g_marshal_value_peek_boxed (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - data2); -} -#define dbus_glib_marshal_nm_device_wifi_NONE__BOXED_POINTER dbus_glib_marshal_nm_device_wifi_VOID__BOXED_POINTER - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_wifi_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_wifi_methods[] = { - { (GCallback) impl_device_get_access_points, dbus_glib_marshal_nm_device_wifi_BOOLEAN__POINTER_POINTER, 0 }, - { (GCallback) impl_device_get_all_access_points, dbus_glib_marshal_nm_device_wifi_BOOLEAN__POINTER_POINTER, 89 }, - { (GCallback) impl_device_request_scan, dbus_glib_marshal_nm_device_wifi_NONE__BOXED_POINTER, 181 }, -}; - -const DBusGObjectInfo dbus_glib_nm_device_wifi_object_info = { 1, - dbus_glib_nm_device_wifi_methods, - 3, -"org.freedesktop.NetworkManager.Device.Wireless\0GetAccessPoints\0S\0access_points\0O\0F\0N\0ao\0\0org.freedesktop.NetworkManager.Device.Wireless\0GetAllAccessPoints\0S\0access_points\0O\0F\0N\0ao\0\0org.freedesktop.NetworkManager.Device.Wireless\0RequestScan\0A\0options\0I\0a{sv}\0\0\0", -"org.freedesktop.NetworkManager.Device.Wireless\0PropertiesChanged\0org.freedesktop.NetworkManager.Device.Wireless\0AccessPointAdded\0org.freedesktop.NetworkManager.Device.Wireless\0AccessPointRemoved\0\0", -"org.freedesktop.NetworkManager.Device.Wireless\0HwAddress\0hw_address\0read\0org.freedesktop.NetworkManager.Device.Wireless\0PermHwAddress\0perm_hw_address\0read\0org.freedesktop.NetworkManager.Device.Wireless\0Mode\0mode\0read\0org.freedesktop.NetworkManager.Device.Wireless\0Bitrate\0bitrate\0read\0org.freedesktop.NetworkManager.Device.Wireless\0AccessPoints\0access_points\0read\0org.freedesktop.NetworkManager.Device.Wireless\0ActiveAccessPoint\0active_access_point\0read\0org.freedesktop.NetworkManager.Device.Wireless\0WirelessCapabilities\0wireless_capabilities\0read\0\0" -}; - diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 1bf64bcc..64da03e1 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -21,21 +21,16 @@ #include "config.h" -#include -#include -#include #include #include #include #include -#include "nm-glib-compat.h" -#include "nm-dbus-manager.h" +#include "nm-default.h" #include "nm-device.h" #include "nm-device-wifi.h" #include "nm-device-private.h" #include "nm-utils.h" -#include "nm-logging.h" #include "NetworkManagerUtils.h" #include "nm-activation-request.h" #include "nm-supplicant-manager.h" @@ -52,25 +47,11 @@ #include "nm-auth-utils.h" #include "nm-settings-connection.h" #include "nm-enum-types.h" -#include "nm-dbus-glib-types.h" -#include "nm-wifi-enum-types.h" #include "nm-connection-provider.h" -#include "gsystem-local-alloc.h" +#include "nm-core-internal.h" +#include "nm-config.h" - -static gboolean impl_device_get_access_points (NMDeviceWifi *device, - GPtrArray **aps, - GError **err); - -static gboolean impl_device_get_all_access_points (NMDeviceWifi *device, - GPtrArray **aps, - GError **err); - -static void impl_device_request_scan (NMDeviceWifi *device, - GHashTable *options, - DBusGMethodInvocation *context); - -#include "nm-device-wifi-glue.h" +#include "nmdbus-device-wifi.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceWifi); @@ -111,29 +92,27 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; struct _NMDeviceWifiPrivate { - gboolean disposed; - gint8 invalid_strength_counter; - GSList * ap_list; + GHashTable * aps; NMAccessPoint * current_ap; guint32 rate; gboolean enabled; /* rfkilled or not */ + gint32 last_scan; gint32 scheduled_scan_time; guint8 scan_interval; /* seconds */ guint pending_scan_id; - guint scanlist_cull_id; - gboolean requested_scan; + guint ap_dump_id; + bool requested_scan; NMSupplicantManager *sup_mgr; NMSupplicantInterface *sup_iface; guint sup_timeout_id; /* supplicant association timeout */ - gboolean ssid_found; + bool ssid_found; NM80211Mode mode; - guint32 failed_link_count; guint periodic_source_id; guint link_timeout_id; guint32 failed_iface_count; @@ -164,7 +143,7 @@ static void supplicant_iface_new_bss_cb (NMSupplicantInterface * iface, static void supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, const char *object_path, - GHashTable *properties, + GVariant *properties, NMDeviceWifi *self); static void supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface, @@ -179,49 +158,34 @@ static void supplicant_iface_notify_scanning_cb (NMSupplicantInterface * iface, GParamSpec * pspec, NMDeviceWifi * self); -static void schedule_scanlist_cull (NMDeviceWifi *self); +static void supplicant_iface_notify_current_bss (NMSupplicantInterface *iface, + GParamSpec *pspec, + NMDeviceWifi *self); -static void request_wireless_scan (NMDeviceWifi *self, GHashTable *scan_options); +static void request_wireless_scan (NMDeviceWifi *self, GVariant *scan_options); -static void remove_access_point (NMDeviceWifi *device, NMAccessPoint *ap); +static void ap_add_remove (NMDeviceWifi *self, + guint signum, + NMAccessPoint *ap, + gboolean recheck_available_connections); static void remove_supplicant_interface_error_handler (NMDeviceWifi *self); /*****************************************************************/ -static GObject* -constructor (GType type, - guint n_construct_params, - GObjectConstructParam *construct_params) +static void +constructed (GObject *object) { - GObject *object; - GObjectClass *klass; - NMDeviceWifi *self; - NMDeviceWifiPrivate *priv; + NMDeviceWifi *self = NM_DEVICE_WIFI (object); + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - klass = G_OBJECT_CLASS (nm_device_wifi_parent_class); - object = klass->constructor (type, n_construct_params, construct_params); - if (!object) - return NULL; - - self = NM_DEVICE_WIFI (object); - priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - if (!nm_platform_wifi_get_capabilities (NM_PLATFORM_GET, - nm_device_get_ifindex (NM_DEVICE (self)), - &priv->capabilities)) { - _LOGW (LOGD_HW | LOGD_WIFI, "failed to initialize WiFi driver"); - g_object_unref (object); - return NULL; - } + G_OBJECT_CLASS (nm_device_wifi_parent_class)->constructed (object); if (priv->capabilities & NM_WIFI_DEVICE_CAP_AP) _LOGI (LOGD_HW | LOGD_WIFI, "driver supports Access Point (AP) mode"); /* Connect to the supplicant manager */ priv->sup_mgr = g_object_ref (nm_supplicant_manager_get ()); - - return object; } static gboolean @@ -268,6 +232,10 @@ supplicant_interface_acquire (NMDeviceWifi *self) "notify::scanning", G_CALLBACK (supplicant_iface_notify_scanning_cb), self); + g_signal_connect (priv->sup_iface, + "notify::" NM_SUPPLICANT_INTERFACE_CURRENT_BSS, + G_CALLBACK (supplicant_iface_notify_current_bss), + self); return TRUE; } @@ -288,10 +256,7 @@ supplicant_interface_release (NMDeviceWifi *self) _LOGD (LOGD_WIFI_SCAN, "reset scanning interval to %d seconds", priv->scan_interval); - if (priv->scanlist_cull_id) { - g_source_remove (priv->scanlist_cull_id); - priv->scanlist_cull_id = 0; - } + nm_clear_g_source (&priv->ap_dump_id); if (priv->sup_iface) { remove_supplicant_interface_error_handler (self); @@ -310,177 +275,30 @@ supplicant_interface_release (NMDeviceWifi *self) static NMAccessPoint * get_ap_by_path (NMDeviceWifi *self, const char *path) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - GSList *iter; + g_return_val_if_fail (path != NULL, NULL); + return g_hash_table_lookup (NM_DEVICE_WIFI_GET_PRIVATE (self)->aps, path); - if (!path) - return NULL; - - for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) { - if (g_strcmp0 (path, nm_ap_get_dbus_path (NM_AP (iter->data))) == 0) - return NM_AP (iter->data); - } - return NULL; } static NMAccessPoint * get_ap_by_supplicant_path (NMDeviceWifi *self, const char *path) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - GSList *iter; + GHashTableIter iter; + NMAccessPoint *ap; - if (!path) - return NULL; + g_return_val_if_fail (path != NULL, NULL); - for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) { - if (g_strcmp0 (path, nm_ap_get_supplicant_path (NM_AP (iter->data))) == 0) - return NM_AP (iter->data); + g_hash_table_iter_init (&iter, NM_DEVICE_WIFI_GET_PRIVATE (self)->aps); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &ap)) { + if (g_strcmp0 (path, nm_ap_get_supplicant_path (ap)) == 0) + return ap; } return NULL; } -static NMAccessPoint * -find_active_ap (NMDeviceWifi *self, - NMAccessPoint *ignore_ap, - gboolean match_hidden) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - int ifindex = nm_device_get_ifindex (NM_DEVICE (self)); - guint8 bssid[ETH_ALEN]; - GByteArray *ssid; - GSList *iter; - int i = 0; - NMAccessPoint *match_nofreq = NULL, *active_ap = NULL; - gboolean found_a_band = FALSE; - gboolean found_bg_band = FALSE; - NM80211Mode devmode; - guint32 devfreq; - - nm_platform_wifi_get_bssid (NM_PLATFORM_GET, ifindex, bssid); - _LOGD (LOGD_WIFI, "active BSSID: %02x:%02x:%02x:%02x:%02x:%02x", - bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); - - if (!nm_ethernet_address_is_valid (bssid, ETH_ALEN)) - return NULL; - - ssid = nm_platform_wifi_get_ssid (NM_PLATFORM_GET, ifindex); - _LOGD (LOGD_WIFI, "active SSID: %s%s%s", - ssid ? "'" : "", - ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)", - ssid ? "'" : ""); - - devmode = nm_platform_wifi_get_mode (NM_PLATFORM_GET, ifindex); - devfreq = nm_platform_wifi_get_frequency (NM_PLATFORM_GET, ifindex); - - /* When matching hidden APs, do a second pass that ignores the SSID check, - * because NM might not yet know the SSID of the hidden AP in the scan list - * and therefore it won't get matched the first time around. - */ - while (i++ < (match_hidden ? 2 : 1)) { - _LOGD (LOGD_WIFI, " Pass #%d %s", i, i > 1 ? "(ignoring SSID)" : ""); - - /* Find this SSID + BSSID in the device's AP list */ - for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) { - NMAccessPoint *ap = NM_AP (iter->data); - const char *ap_bssid = nm_ap_get_address (ap); - const GByteArray *ap_ssid = nm_ap_get_ssid (ap); - NM80211Mode apmode; - guint32 apfreq; - - _LOGD (LOGD_WIFI, " AP: %s%s%s %s", - ap_ssid ? "'" : "", - ap_ssid ? nm_utils_escape_ssid (ap_ssid->data, ap_ssid->len) : "(none)", - ap_ssid ? "'" : "", - str_if_set (ap_bssid, "(none)")); - - if (ap == ignore_ap) { - _LOGD (LOGD_WIFI, " ignored"); - continue; - } - - if (!nm_utils_hwaddr_matches (bssid, ETH_ALEN, ap_bssid, -1)) { - _LOGD (LOGD_WIFI, " BSSID mismatch"); - continue; - } - - if (i == 0) { - if ( (ssid && !ap_ssid) - || (ap_ssid && !ssid) - || (ssid && ap_ssid && !nm_utils_same_ssid (ssid->data, ssid->len, - ap_ssid->data, ap_ssid->len, - TRUE))) { - _LOGD (LOGD_WIFI, " SSID mismatch"); - continue; - } - } - - apmode = nm_ap_get_mode (ap); - if (devmode != apmode) { - _LOGD (LOGD_WIFI, " mode mismatch (device %d, ap %d)", - devmode, apmode); - continue; - } - - apfreq = nm_ap_get_freq (ap); - if (devfreq != apfreq) { - _LOGD (LOGD_WIFI, " frequency mismatch (device %u, ap %u)", - devfreq, apfreq); - - if (match_nofreq == NULL) - match_nofreq = ap; - - if (apfreq > 4000) - found_a_band = TRUE; - else if (apfreq > 2000) - found_bg_band = TRUE; - continue; - } - - // FIXME: handle security settings here too - _LOGD (LOGD_WIFI, " matched"); - active_ap = ap; - goto done; - } - } - - /* Some proprietary drivers (wl.o) report tuned frequency (like when - * scanning) instead of the associated AP's frequency. This is a great - * example of how WEXT is underspecified. We use frequency to find the - * active AP in the scan list because some configurations use the same - * SSID/BSSID on the 2GHz and 5GHz bands simultaneously, and we need to - * make sure we get the right AP in the right band. This configuration - * is uncommon though, and the frequency check penalizes closed drivers we - * can't fix. Because we're not total dicks, ignore the frequency condition - * if the associated BSSID/SSID exists only in one band since that's most - * likely the AP we want. Sometimes wl.o returns a frequency of 0, so if - * we can't match the AP based on frequency at all, just give up. - */ - if (match_nofreq && ((found_a_band != found_bg_band) || (devfreq == 0))) { - const GByteArray *ap_ssid = nm_ap_get_ssid (match_nofreq); - - _LOGD (LOGD_WIFI, " matched %s%s%s %s", - ap_ssid ? "'" : "", - ap_ssid ? nm_utils_escape_ssid (ap_ssid->data, ap_ssid->len) : "(none)", - ap_ssid ? "'" : "", - str_if_set (nm_ap_get_address (match_nofreq), "(none)")); - - active_ap = match_nofreq; - goto done; - } - - _LOGD (LOGD_WIFI, " No matching AP found."); - -done: - if (ssid) - g_byte_array_free (ssid, TRUE); - return active_ap; -} - static void update_seen_bssids_cache (NMDeviceWifi *self, NMAccessPoint *ap) { - NMConnection *connection; - g_return_if_fail (NM_IS_DEVICE_WIFI (self)); if (ap == NULL) @@ -490,12 +308,10 @@ update_seen_bssids_cache (NMDeviceWifi *self, NMAccessPoint *ap) if (nm_ap_get_mode (ap) != NM_802_11_MODE_INFRA) return; - if (nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_ACTIVATED) { - connection = nm_device_get_connection (NM_DEVICE (self)); - if (connection) { - nm_settings_connection_add_seen_bssid (NM_SETTINGS_CONNECTION (connection), - nm_ap_get_address (ap)); - } + if ( nm_device_get_state (NM_DEVICE (self)) == NM_DEVICE_STATE_ACTIVATED + && nm_device_has_unmodified_applied_connection (NM_DEVICE (self), NM_SETTING_COMPARE_FLAG_NONE)) { + nm_settings_connection_add_seen_bssid (nm_device_get_settings_connection (NM_DEVICE (self)), + nm_ap_get_address (ap)); } } @@ -516,13 +332,6 @@ set_current_ap (NMDeviceWifi *self, NMAccessPoint *new_ap, gboolean recheck_avai if (new_ap) { priv->current_ap = g_object_ref (new_ap); - /* Move the current AP to the front of the scan list. Since we - * do a lot of searches looking for the current AP, it saves - * time to have it in front. - */ - priv->ap_list = g_slist_remove (priv->ap_list, new_ap); - priv->ap_list = g_slist_prepend (priv->ap_list, new_ap); - /* Update seen BSSIDs cache */ update_seen_bssids_cache (self, priv->current_ap); } else @@ -531,11 +340,9 @@ set_current_ap (NMDeviceWifi *self, NMAccessPoint *new_ap, gboolean recheck_avai if (old_ap) { NM80211Mode mode = nm_ap_get_mode (old_ap); - if (mode == NM_802_11_MODE_ADHOC || mode == NM_802_11_MODE_AP || nm_ap_get_fake (old_ap)) { - remove_access_point (self, old_ap); - if (recheck_available_connections) - nm_device_recheck_available_connections (NM_DEVICE (self)); - } + /* Remove any AP from the internal list if it was created by NM or isn't known to the supplicant */ + if (mode == NM_802_11_MODE_ADHOC || mode == NM_802_11_MODE_AP || nm_ap_get_fake (old_ap)) + ap_add_remove (self, ACCESS_POINT_REMOVED, old_ap, recheck_available_connections); g_object_unref (old_ap); } @@ -543,11 +350,10 @@ set_current_ap (NMDeviceWifi *self, NMAccessPoint *new_ap, gboolean recheck_avai } static void -periodic_update (NMDeviceWifi *self, NMAccessPoint *ignore_ap) +periodic_update (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); int ifindex = nm_device_get_ifindex (NM_DEVICE (self)); - NMAccessPoint *new_ap; guint32 new_rate; int percent; NMDeviceState state; @@ -574,65 +380,15 @@ periodic_update (NMDeviceWifi *self, NMAccessPoint *ignore_ap) if (priv->mode == NM_802_11_MODE_AP) return; - /* In IBSS mode, most newer firmware/drivers do "BSS coalescing" where - * multiple IBSS stations using the same SSID will eventually switch to - * using the same BSSID to avoid network segmentation. When this happens, - * the card's reported BSSID will change, but the new BSS may not - * be in the scan list, since scanning isn't done in ad-hoc mode for - * various reasons. So pull the BSSID from the card and update the - * current AP with it, if the current AP is adhoc. - */ - if (priv->current_ap && (nm_ap_get_mode (priv->current_ap) == NM_802_11_MODE_ADHOC)) { - guint8 bssid[ETH_ALEN] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; - - nm_platform_wifi_get_bssid (NM_PLATFORM_GET, ifindex, bssid); - /* 0x02 means "locally administered" and should be OR-ed into - * the first byte of IBSS BSSIDs. - */ - if ((bssid[0] & 0x02) && nm_ethernet_address_is_valid (bssid, ETH_ALEN)) { - char *bssid_str = nm_utils_hwaddr_ntoa (bssid, ETH_ALEN); - nm_ap_set_address (priv->current_ap, bssid_str); - g_free (bssid_str); - } - } - - new_ap = find_active_ap (self, ignore_ap, FALSE); - if (new_ap) { - /* Try to smooth out the strength. Atmel cards, for example, will give no strength - * one second and normal strength the next. - */ + if (priv->current_ap) { + /* Smooth out the strength to work around crappy drivers */ percent = nm_platform_wifi_get_quality (NM_PLATFORM_GET, ifindex); if (percent >= 0 || ++priv->invalid_strength_counter > 3) { - nm_ap_set_strength (new_ap, (gint8) percent); + nm_ap_set_strength (priv->current_ap, (gint8) percent); priv->invalid_strength_counter = 0; } } - if (new_ap != priv->current_ap) { - const char *new_bssid = NULL; - const GByteArray *new_ssid = NULL; - const char *old_bssid = NULL; - const GByteArray *old_ssid = NULL; - - if (new_ap) { - new_bssid = nm_ap_get_address (new_ap); - new_ssid = nm_ap_get_ssid (new_ap); - } - - if (priv->current_ap) { - old_bssid = nm_ap_get_address (priv->current_ap); - old_ssid = nm_ap_get_ssid (priv->current_ap); - } - - _LOGI (LOGD_WIFI, "roamed from BSSID %s (%s) to %s (%s)", - old_bssid ? old_bssid : "(none)", - old_ssid ? nm_utils_escape_ssid (old_ssid->data, old_ssid->len) : "(none)", - new_bssid ? new_bssid : "(none)", - new_ssid ? nm_utils_escape_ssid (new_ssid->data, new_ssid->len) : "(none)"); - - set_current_ap (self, new_ap, TRUE); - } - new_rate = nm_platform_wifi_get_rate (NM_PLATFORM_GET, ifindex); if (new_rate != priv->rate) { priv->rate = new_rate; @@ -643,10 +399,18 @@ periodic_update (NMDeviceWifi *self, NMAccessPoint *ignore_ap) static gboolean periodic_update_cb (gpointer user_data) { - periodic_update (NM_DEVICE_WIFI (user_data), NULL); + periodic_update (NM_DEVICE_WIFI (user_data)); return TRUE; } +static void +realize_start_notify (NMDevice *device, const NMPlatformLink *plink) +{ + NM_DEVICE_CLASS (nm_device_wifi_parent_class)->realize_start_notify (device, plink); + + g_object_notify (G_OBJECT (device), NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS); +} + static gboolean bring_up (NMDevice *device, gboolean *no_firmware) { @@ -657,47 +421,55 @@ bring_up (NMDevice *device, gboolean *no_firmware) } static void -emit_ap_added_removed (NMDeviceWifi *self, - guint signum, - NMAccessPoint *ap, - gboolean recheck_available_connections) +ap_add_remove (NMDeviceWifi *self, + guint signum, + NMAccessPoint *ap, + gboolean recheck_available_connections) { + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + + nm_assert (NM_IN_SET (signum, ACCESS_POINT_ADDED, ACCESS_POINT_REMOVED)); + + if (signum == ACCESS_POINT_ADDED) { + g_hash_table_insert (priv->aps, + (gpointer) nm_exported_object_export ((NMExportedObject *) ap), + g_object_ref (ap)); + } + g_signal_emit (self, signals[signum], 0, ap); g_object_notify (G_OBJECT (self), NM_DEVICE_WIFI_ACCESS_POINTS); + + if (signum == ACCESS_POINT_REMOVED) { + g_hash_table_remove (priv->aps, nm_exported_object_get_path ((NMExportedObject *) ap)); + nm_exported_object_unexport ((NMExportedObject *) ap); + g_object_unref (ap); + } + nm_device_emit_recheck_auto_activate (NM_DEVICE (self)); if (recheck_available_connections) nm_device_recheck_available_connections (NM_DEVICE (self)); } -static void -remove_access_point (NMDeviceWifi *device, - NMAccessPoint *ap) -{ - NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - g_return_if_fail (ap); - g_return_if_fail (ap != priv->current_ap); - g_return_if_fail (g_slist_find (priv->ap_list, ap)); - - priv->ap_list = g_slist_remove (priv->ap_list, ap); - emit_ap_added_removed (self, ACCESS_POINT_REMOVED, ap, FALSE); - g_object_unref (ap); -} - static void remove_all_aps (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + GHashTableIter iter; + NMAccessPoint *ap; - if (priv->ap_list) { - set_current_ap (self, NULL, FALSE); + if (!g_hash_table_size (priv->aps)) + return; - while (priv->ap_list) - remove_access_point (self, NM_AP (priv->ap_list->data)); + set_current_ap (self, NULL, FALSE); - nm_device_recheck_available_connections (NM_DEVICE (self)); +again: + g_hash_table_iter_init (&iter, priv->aps); + if (g_hash_table_iter_next (&iter, NULL, (gpointer) &ap)) { + ap_add_remove (self, ACCESS_POINT_REMOVED, ap, FALSE); + goto again; } + + nm_device_recheck_available_connections (NM_DEVICE (self)); } static void @@ -706,29 +478,14 @@ deactivate (NMDevice *device) NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); int ifindex = nm_device_get_ifindex (device); - NMConnection *connection; NM80211Mode old_mode = priv->mode; - connection = nm_device_get_connection (device); - if (connection) { - /* Clear wireless secrets tries when deactivating */ - g_object_set_data (G_OBJECT (connection), WIRELESS_SECRETS_TRIES, NULL); - } - - if (priv->periodic_source_id) { - g_source_remove (priv->periodic_source_id); - priv->periodic_source_id = 0; - } + nm_clear_g_source (&priv->periodic_source_id); cleanup_association_attempt (self, TRUE); priv->rate = 0; - /* If the AP is 'fake', i.e. it wasn't actually found from - * a scan but the user tried to connect to it manually (maybe it - * was non-broadcasting or something) get rid of it, because 'fake' - * APs should only live for as long as we're connected to them. - **/ set_current_ap (self, NULL, TRUE); /* Clear any critical protocol notification in the Wi-Fi stack */ @@ -738,6 +495,8 @@ deactivate (NMDevice *device) if (nm_device_get_initial_hw_address (device)) nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_WIFI); + nm_platform_wifi_set_powersave (NM_PLATFORM_GET, ifindex, 0); + /* Ensure we're in infrastructure mode after deactivation; some devices * (usually older ones) don't scan well in adhoc mode. */ @@ -848,7 +607,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) return FALSE; if (priv->sup_iface) { - if (nm_supplicant_interface_get_ap_support (priv->sup_iface) == AP_SUPPORT_NO) + if (nm_supplicant_interface_get_ap_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_NO) return FALSE; } } @@ -860,6 +619,28 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) return TRUE; } +static NMAccessPoint * +find_first_compatible_ap (NMDeviceWifi *self, + NMConnection *connection, + gboolean allow_unstable_order) +{ + GHashTableIter iter; + NMAccessPoint *ap; + NMAccessPoint *cand_ap = NULL; + + g_return_val_if_fail (connection != NULL, NULL); + + g_hash_table_iter_init (&iter, NM_DEVICE_WIFI_GET_PRIVATE (self)->aps); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &ap)) { + if (!nm_ap_check_compatible (ap, connection)) + continue; + if (allow_unstable_order) + return ap; + if (!cand_ap || (nm_ap_get_id (cand_ap) < nm_ap_get_id (ap))) + cand_ap = ap; + } + return cand_ap; +} static gboolean check_connection_available (NMDevice *device, @@ -867,10 +648,8 @@ check_connection_available (NMDevice *device, NMDeviceCheckConAvailableFlags flags, const char *specific_object) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device); NMSettingWireless *s_wifi; const char *mode; - GSList *ap_iter = NULL; s_wifi = nm_connection_get_setting_wireless (connection); g_return_val_if_fail (s_wifi, FALSE); @@ -904,13 +683,8 @@ check_connection_available (NMDevice *device, if (nm_setting_wireless_get_hidden (s_wifi) || NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_IGNORE_AP)) return TRUE; - /* check if its visible */ - for (ap_iter = priv->ap_list; ap_iter; ap_iter = g_slist_next (ap_iter)) { - if (nm_ap_check_compatible (NM_AP (ap_iter->data), connection)) - return TRUE; - } - - return FALSE; + /* check at least one AP is compatible with this connection */ + return !!find_first_compatible_ap (NM_DEVICE_WIFI (device), connection, TRUE); } /* @@ -957,7 +731,6 @@ complete_connection (NMDevice *device, GError **error) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMSettingWireless *s_wifi; const char *setting_mac; char *str_ssid = NULL; @@ -965,7 +738,6 @@ complete_connection (NMDevice *device, const GByteArray *ssid = NULL; GByteArray *tmp_ssid = NULL; GBytes *setting_ssid = NULL; - GSList *iter; gboolean hidden = FALSE; const char *perm_hw_addr; @@ -991,12 +763,7 @@ complete_connection (NMDevice *device, } /* Find a compatible AP in the scan list */ - for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) { - if (nm_ap_check_compatible (NM_AP (iter->data), connection)) { - ap = NM_AP (iter->data); - break; - } - } + ap = find_first_compatible_ap (self, connection, FALSE); /* If we still don't have an AP, then the WiFI settings needs to be * fully specified by the client. Might not be able to find an AP @@ -1159,8 +926,7 @@ can_auto_connect (NMDevice *device, char **specific_object) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - GSList *ap_iter; + NMAccessPoint *ap; const char *method = NULL; guint64 timestamp = 0; @@ -1181,130 +947,141 @@ can_auto_connect (NMDevice *device, if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_SHARED)) return TRUE; - for (ap_iter = priv->ap_list; ap_iter; ap_iter = g_slist_next (ap_iter)) { - NMAccessPoint *ap = NM_AP (ap_iter->data); - - if (nm_ap_check_compatible (ap, connection)) { - /* All good; connection is usable */ - *specific_object = (char *) nm_ap_get_dbus_path (ap); - return TRUE; - } + ap = find_first_compatible_ap (self, connection, FALSE); + if (ap) { + /* All good; connection is usable */ + *specific_object = (char *) nm_exported_object_get_path (NM_EXPORTED_OBJECT (ap)); + return TRUE; } return FALSE; } -static void -ap_list_dump (NMDeviceWifi *self) +static gint +ap_id_compare (NMAccessPoint *a, NMAccessPoint *b) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - GSList * elt; - int i = 0; + guint32 a_id = nm_ap_get_id (a); + guint32 b_id = nm_ap_get_id (b); - g_return_if_fail (NM_IS_DEVICE_WIFI (self)); + return a_id < b_id ? -1 : (a_id == b_id ? 0 : 1); +} - _LOGD (LOGD_WIFI_SCAN, "Current AP list:"); - for (elt = priv->ap_list; elt; elt = g_slist_next (elt), i++) { - NMAccessPoint * ap = NM_AP (elt->data); - nm_ap_dump (ap, "List AP: "); - } - _LOGD (LOGD_WIFI_SCAN, "Current AP list: done"); +static GSList * +get_sorted_ap_list (NMDeviceWifi *self) +{ + GSList *sorted = NULL; + GHashTableIter iter; + NMAccessPoint *ap; + + g_hash_table_iter_init (&iter, NM_DEVICE_WIFI_GET_PRIVATE (self)->aps); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &ap)) + sorted = g_slist_prepend (sorted, ap); + return g_slist_sort (sorted, (GCompareFunc) ap_id_compare); } -static gboolean -impl_device_get_access_points (NMDeviceWifi *self, - GPtrArray **aps, - GError **err) +static void +impl_device_wifi_get_access_points (NMDeviceWifi *self, + GDBusMethodInvocation *context) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - GSList *elt; + GSList *sorted, *iter; + GPtrArray *paths; - *aps = g_ptr_array_new (); - for (elt = priv->ap_list; elt; elt = g_slist_next (elt)) { - NMAccessPoint *ap = NM_AP (elt->data); + paths = g_ptr_array_new (); + sorted = get_sorted_ap_list (self); + for (iter = sorted; iter; iter = iter->next) { + NMAccessPoint *ap = NM_AP (iter->data); if (nm_ap_get_ssid (ap)) - g_ptr_array_add (*aps, g_strdup (nm_ap_get_dbus_path (ap))); + g_ptr_array_add (paths, g_strdup (nm_exported_object_get_path (NM_EXPORTED_OBJECT (ap)))); } - return TRUE; + g_ptr_array_add (paths, NULL); + g_slist_free (sorted); + + g_dbus_method_invocation_return_value (context, g_variant_new ("(^ao)", (char **) paths->pdata)); + g_ptr_array_unref (paths); } -static gboolean -impl_device_get_all_access_points (NMDeviceWifi *self, - GPtrArray **aps, - GError **err) +static void +impl_device_wifi_get_all_access_points (NMDeviceWifi *self, + GDBusMethodInvocation *context) { - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - GSList *elt; + GSList *sorted, *iter; + GPtrArray *paths; - *aps = g_ptr_array_new (); - for (elt = priv->ap_list; elt; elt = g_slist_next (elt)) - g_ptr_array_add (*aps, g_strdup (nm_ap_get_dbus_path (NM_AP (elt->data)))); - return TRUE; + paths = g_ptr_array_new (); + sorted = get_sorted_ap_list (self); + for (iter = sorted; iter; iter = iter->next) + g_ptr_array_add (paths, g_strdup (nm_exported_object_get_path (NM_EXPORTED_OBJECT (iter->data)))); + g_ptr_array_add (paths, NULL); + g_slist_free (sorted); + + g_dbus_method_invocation_return_value (context, g_variant_new ("(^ao)", (char **) paths->pdata)); + g_ptr_array_unref (paths); } static void request_scan_cb (NMDevice *device, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, + NMAuthSubject *subject, GError *error, gpointer user_data) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); - GError *local = NULL; - gs_unref_hashtable GHashTable *new_scan_options = user_data; + gs_unref_variant GVariant *new_scan_options = user_data; if (error) { - dbus_g_method_return_error (context, error); + g_dbus_method_invocation_return_gerror (context, error); return; } if (!check_scanning_allowed (self)) { - local = g_error_new_literal (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, - "Scanning not allowed at this time"); - dbus_g_method_return_error (context, local); - g_error_free (local); + g_dbus_method_invocation_return_error_literal (context, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ALLOWED, + "Scanning not allowed at this time"); return; } cancel_pending_scan (self); request_wireless_scan (self, new_scan_options); - dbus_g_method_return (context); + g_dbus_method_invocation_return_value (context, NULL); } static void -impl_device_request_scan (NMDeviceWifi *self, - GHashTable *options, - DBusGMethodInvocation *context) +impl_device_wifi_request_scan (NMDeviceWifi *self, + GDBusMethodInvocation *context, + GVariant *options) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); gint32 last_scan; - GError *error; if ( !priv->enabled || !priv->sup_iface || nm_device_get_state (device) < NM_DEVICE_STATE_DISCONNECTED || nm_device_is_activating (device)) { - error = g_error_new_literal (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, - "Scanning not allowed while unavailable or activating"); - goto error; + g_dbus_method_invocation_return_error_literal (context, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ALLOWED, + "Scanning not allowed while unavailable or activating"); + return; } if (nm_supplicant_interface_get_scanning (priv->sup_iface)) { - error = g_error_new_literal (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, - "Scanning not allowed while already scanning"); - goto error; + g_dbus_method_invocation_return_error_literal (context, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ALLOWED, + "Scanning not allowed while already scanning"); + return; } last_scan = nm_supplicant_interface_get_last_scan_time (priv->sup_iface); if (last_scan && (nm_utils_get_monotonic_timestamp_s () - last_scan) < 10) { - error = g_error_new_literal (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_NOT_ALLOWED, - "Scanning not allowed immediately following previous scan"); - goto error; + g_dbus_method_invocation_return_error_literal (context, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_NOT_ALLOWED, + "Scanning not allowed immediately following previous scan"); + return; } /* Ask the manager to authenticate this request for us */ @@ -1315,12 +1092,7 @@ impl_device_request_scan (NMDeviceWifi *self, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE, request_scan_cb, - options ? g_hash_table_ref (options) : NULL); - return; - -error: - dbus_g_method_return_error (context, error); - g_error_free (error); + options ? g_variant_ref (options) : NULL); } static gboolean @@ -1367,7 +1139,7 @@ scanning_allowed (NMDeviceWifi *self) || nm_supplicant_interface_get_scanning (priv->sup_iface)) return FALSE; - connection = nm_device_get_connection (NM_DEVICE (self)); + connection = nm_device_get_applied_connection (NM_DEVICE (self)); if (connection) { NMSettingWireless *s_wifi; const char *ip4_method = NULL; @@ -1481,8 +1253,32 @@ build_hidden_probe_list (NMDeviceWifi *self) return ssids; } +static GPtrArray * +ssids_options_to_ptrarray (GVariant *value) +{ + GPtrArray *ssids = NULL; + GByteArray *ssid_array; + GVariant *v; + const guint8 *bytes; + gsize len; + int num_ssids, i; + + num_ssids = g_variant_n_children (value); + if (num_ssids) { + ssids = g_ptr_array_new_full (num_ssids, (GDestroyNotify) g_byte_array_unref); + for (i = 0; i < num_ssids; i++) { + v = g_variant_get_child_value (value, i); + bytes = g_variant_get_fixed_array (v, &len, sizeof (guint8)); + ssid_array = g_byte_array_new (); + g_byte_array_append (ssid_array, bytes, len); + g_ptr_array_add (ssids, ssid_array); + } + } + return ssids; +} + static void -request_wireless_scan (NMDeviceWifi *self, GHashTable *scan_options) +request_wireless_scan (NMDeviceWifi *self, GVariant *scan_options) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); gboolean backoff = FALSE; @@ -1496,13 +1292,16 @@ request_wireless_scan (NMDeviceWifi *self, GHashTable *scan_options) if (check_scanning_allowed (self)) { _LOGD (LOGD_WIFI_SCAN, "scanning requested"); - if (scan_options && g_hash_table_size (scan_options)) { - GValue *val = g_hash_table_lookup (scan_options, "ssids"); + if (scan_options) { + GVariant *val = g_variant_lookup_value (scan_options, "ssids", NULL); - if (val && G_VALUE_HOLDS (val, DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UCHAR)) - ssids = g_ptr_array_ref (g_value_get_boxed (val)); - else - _LOGD (LOGD_WIFI_SCAN, "ignoring invalid scan options"); + if (val) { + if (g_variant_is_of_type (val, G_VARIANT_TYPE ("aay"))) + ssids = ssids_options_to_ptrarray (val); + else + _LOGD (LOGD_WIFI_SCAN, "ignoring invalid 'ssids' scan option"); + g_variant_unref (val); + } } if (!ssids) ssids = build_hidden_probe_list (self); @@ -1606,10 +1405,7 @@ cancel_pending_scan (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - if (priv->pending_scan_id) { - g_source_remove (priv->pending_scan_id); - priv->pending_scan_id = 0; - } + nm_clear_g_source (&priv->pending_scan_id); } static void @@ -1621,13 +1417,9 @@ supplicant_iface_scan_done_cb (NMSupplicantInterface *iface, _LOGD (LOGD_WIFI_SCAN, "scan %s", success ? "successful" : "failed"); + priv->last_scan = nm_utils_get_monotonic_timestamp_s (); schedule_scan (self, success); - /* Ensure that old APs get removed, which otherwise only - * happens when there are new BSSes. - */ - schedule_scanlist_cull (self); - if (priv->requested_scan) { priv->requested_scan = FALSE; nm_device_remove_pending_action (NM_DEVICE (self), "scan", TRUE); @@ -1639,7 +1431,35 @@ supplicant_iface_scan_done_cb (NMSupplicantInterface *iface, * */ -#define WPAS_REMOVED_TAG "supplicant-removed" +static gboolean +ap_list_dump (gpointer user_data) +{ + NMDeviceWifi *self = NM_DEVICE_WIFI (user_data); + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + GSList *sorted, *iter; + + priv->ap_dump_id = 0; + _LOGD (LOGD_WIFI_SCAN, "APs: [now:%u last:%u next:%u]", + nm_utils_get_monotonic_timestamp_s (), + priv->last_scan, + priv->scheduled_scan_time); + sorted = get_sorted_ap_list (self); + for (iter = sorted; iter; iter = iter->next) + nm_ap_dump (NM_AP (iter->data), "dump ", nm_device_get_iface (NM_DEVICE (self))); + g_slist_free (sorted); + return G_SOURCE_REMOVE; +} + +static void +schedule_ap_list_dump (NMDeviceWifi *self) +{ + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + + if (!nm_logging_enabled (LOGL_DEBUG, LOGD_WIFI_SCAN)) + return; + nm_clear_g_source (&priv->ap_dump_id); + priv->ap_dump_id = g_timeout_add_seconds (1, ap_list_dump, self); +} static void try_fill_ssid_for_hidden_ap (NMAccessPoint *ap) @@ -1673,213 +1493,77 @@ try_fill_ssid_for_hidden_ap (NMAccessPoint *ap) } } -/* - * merge_scanned_ap - * - * If there is already an entry that matches the BSSID and ESSID of the - * AP to merge, replace that entry with the scanned AP. Otherwise, add - * the scanned AP to the list. - * - * TODO: possibly need to differentiate entries based on security too; i.e. if - * there are two scan results with the same BSSID and SSID but different - * security options? - * - */ static void -merge_scanned_ap (NMDeviceWifi *self, - NMAccessPoint *merge_ap) +supplicant_iface_new_bss_cb (NMSupplicantInterface *iface, + const char *object_path, + GVariant *properties, + NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + NMDeviceState state; + NMAccessPoint *ap; NMAccessPoint *found_ap = NULL; const GByteArray *ssid; - gboolean strict_match = TRUE; + + g_return_if_fail (self != NULL); + g_return_if_fail (properties != NULL); + g_return_if_fail (iface != NULL); + + /* Ignore new APs when unavailable, unmanaged, or in AP mode */ + state = nm_device_get_state (NM_DEVICE (self)); + if (state <= NM_DEVICE_STATE_UNAVAILABLE) + return; + if (NM_DEVICE_WIFI_GET_PRIVATE (self)->mode == NM_802_11_MODE_AP) + return; + + ap = nm_ap_new_from_properties (object_path, properties); + if (!ap) { + _LOGD (LOGD_WIFI_SCAN, "invalid AP properties received for %s", object_path); + return; + } /* Let the manager try to fill in the SSID from seen-bssids lists */ - ssid = nm_ap_get_ssid (merge_ap); + ssid = nm_ap_get_ssid (ap); if (!ssid || nm_utils_is_empty_ssid (ssid->data, ssid->len)) { /* Try to fill the SSID from the AP database */ - try_fill_ssid_for_hidden_ap (merge_ap); + try_fill_ssid_for_hidden_ap (ap); - ssid = nm_ap_get_ssid (merge_ap); + ssid = nm_ap_get_ssid (ap); if (ssid && (nm_utils_is_empty_ssid (ssid->data, ssid->len) == FALSE)) { /* Yay, matched it, no longer treat as hidden */ _LOGD (LOGD_WIFI_SCAN, "matched hidden AP %s => '%s'", - nm_ap_get_address (merge_ap), nm_utils_escape_ssid (ssid->data, ssid->len)); - nm_ap_set_broadcast (merge_ap, FALSE); + nm_ap_get_address (ap), nm_utils_escape_ssid (ssid->data, ssid->len)); } else { /* Didn't have an entry for this AP in the database */ _LOGD (LOGD_WIFI_SCAN, "failed to match hidden AP %s", - nm_ap_get_address (merge_ap)); + nm_ap_get_address (ap)); } } - /* If the incoming scan result matches the hidden AP that NM is currently - * connected to but hasn't been seen in the scan list yet, don't use - * strict matching. Because the capabilities of the fake AP have to be - * constructed from the NMConnection of the activation request, they won't - * always be the same as the capabilities of the real AP from the scan. - */ - if (priv->current_ap && nm_ap_get_fake (priv->current_ap)) - strict_match = FALSE; - - found_ap = get_ap_by_supplicant_path (self, nm_ap_get_supplicant_path (merge_ap)); - if (!found_ap) - found_ap = nm_ap_match_in_list (merge_ap, priv->ap_list, strict_match); + found_ap = get_ap_by_supplicant_path (self, object_path); if (found_ap) { - _LOGD (LOGD_WIFI_SCAN, "merging AP '%s' %s (%p) with existing (%p)", - ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)", - nm_ap_get_address (merge_ap), - merge_ap, - found_ap); - - nm_ap_set_supplicant_path (found_ap, nm_ap_get_supplicant_path (merge_ap)); - nm_ap_set_flags (found_ap, nm_ap_get_flags (merge_ap)); - nm_ap_set_wpa_flags (found_ap, nm_ap_get_wpa_flags (merge_ap)); - nm_ap_set_rsn_flags (found_ap, nm_ap_get_rsn_flags (merge_ap)); - nm_ap_set_strength (found_ap, nm_ap_get_strength (merge_ap)); - nm_ap_set_last_seen (found_ap, nm_ap_get_last_seen (merge_ap)); - nm_ap_set_broadcast (found_ap, nm_ap_get_broadcast (merge_ap)); - nm_ap_set_freq (found_ap, nm_ap_get_freq (merge_ap)); - nm_ap_set_max_bitrate (found_ap, nm_ap_get_max_bitrate (merge_ap)); - - /* If the AP is noticed in a scan, it's automatically no longer - * fake, since it clearly exists somewhere. - */ - nm_ap_set_fake (found_ap, FALSE); - g_object_set_data (G_OBJECT (found_ap), WPAS_REMOVED_TAG, NULL); + nm_ap_dump (ap, "updated ", nm_device_get_iface (NM_DEVICE (self))); + nm_ap_update_from_properties (found_ap, object_path, properties); } else { - /* New entry in the list */ - _LOGD (LOGD_WIFI_SCAN, "adding new AP '%s' %s (%p)", - ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)", - nm_ap_get_address (merge_ap), merge_ap); - - g_object_ref (merge_ap); - priv->ap_list = g_slist_prepend (priv->ap_list, merge_ap); - nm_ap_export_to_dbus (merge_ap); - emit_ap_added_removed (self, ACCESS_POINT_ADDED, merge_ap, TRUE); + nm_ap_dump (ap, "added ", nm_device_get_iface (NM_DEVICE (self))); + ap_add_remove (self, ACCESS_POINT_ADDED, ap, TRUE); } -} -static gboolean -cull_scan_list (NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - gint32 now = nm_utils_get_monotonic_timestamp_s (); - GSList *outdated_list = NULL; - GSList *elt; - guint32 removed = 0, total = 0; - - priv->scanlist_cull_id = 0; - - _LOGD (LOGD_WIFI_SCAN, "checking scan list for outdated APs"); + g_object_unref (ap); - /* Walk the access point list and remove any access points older than - * three times the inactive scan interval. + /* Update the current AP if the supplicant notified a current BSS change + * before it sent the current BSS's scan result. */ - for (elt = priv->ap_list; elt; elt = g_slist_next (elt), total++) { - NMAccessPoint *ap = elt->data; - const guint prune_interval_s = SCAN_INTERVAL_MAX * 3; - gint32 last_seen; - - /* Don't cull the associated AP or manually created APs */ - if (ap == priv->current_ap) - continue; - g_assert (!nm_ap_get_fake (ap)); /* only the current_ap can be fake */ - - /* Don't cull APs still known to the supplicant. Since the supplicant - * doesn't yet emit property updates for "last seen" we have to rely - * on changing signal strength for updating "last seen". But if the - * AP's strength doesn't change we won't get any updates for the AP, - * and we'll end up here even if the AP was still found by the - * supplicant in the last scan. - */ - if ( nm_ap_get_supplicant_path (ap) - && g_object_get_data (G_OBJECT (ap), WPAS_REMOVED_TAG) == NULL) - continue; - - last_seen = nm_ap_get_last_seen (ap); - if (!last_seen || last_seen + prune_interval_s < now) - outdated_list = g_slist_prepend (outdated_list, ap); - } - - /* Remove outdated APs */ - for (elt = outdated_list; elt; elt = g_slist_next (elt)) { - NMAccessPoint *outdated_ap = NM_AP (elt->data); - const GByteArray *ssid; - - ssid = nm_ap_get_ssid (outdated_ap); - _LOGD (LOGD_WIFI_SCAN, - " removing %s (%s%s%s)", - str_if_set (nm_ap_get_address (outdated_ap), "(none)"), - ssid ? "'" : "", - ssid ? nm_utils_escape_ssid (ssid->data, ssid->len) : "(none)", - ssid ? "'" : ""); - - remove_access_point (self, outdated_ap); - removed++; - } - g_slist_free (outdated_list); - - _LOGD (LOGD_WIFI_SCAN, "removed %d APs (of %d)", - removed, total); - - ap_list_dump (self); - - if(removed > 0) - nm_device_recheck_available_connections (NM_DEVICE (self)); - - return FALSE; -} + if (g_strcmp0 (nm_supplicant_interface_get_current_bss (iface), object_path) == 0) + supplicant_iface_notify_current_bss (priv->sup_iface, NULL, self); -static void -schedule_scanlist_cull (NMDeviceWifi *self) -{ - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - /* Cull the scan list after the last request for it has come in */ - if (priv->scanlist_cull_id) - g_source_remove (priv->scanlist_cull_id); - priv->scanlist_cull_id = g_timeout_add_seconds (4, (GSourceFunc) cull_scan_list, self); -} - -static void -supplicant_iface_new_bss_cb (NMSupplicantInterface *iface, - const char *object_path, - GVariant *properties, - NMDeviceWifi *self) -{ - NMDeviceState state; - NMAccessPoint *ap; - - g_return_if_fail (self != NULL); - g_return_if_fail (properties != NULL); - g_return_if_fail (iface != NULL); - - /* Ignore new APs when unavailable, unmanaged, or in AP mode */ - state = nm_device_get_state (NM_DEVICE (self)); - if (state <= NM_DEVICE_STATE_UNAVAILABLE) - return; - if (NM_DEVICE_WIFI_GET_PRIVATE (self)->mode == NM_802_11_MODE_AP) - return; - - ap = nm_ap_new_from_properties (object_path, properties); - if (ap) { - nm_ap_dump (ap, "New AP: "); - - /* Add the AP to the device's AP list */ - merge_scanned_ap (self, ap); - g_object_unref (ap); - } else - _LOGD (LOGD_WIFI_SCAN, "invalid AP properties received for %s", object_path); - - /* Remove outdated access points */ - schedule_scanlist_cull (self); + schedule_ap_list_dump (self); } static void supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, const char *object_path, - GHashTable *properties, + GVariant *properties, NMDeviceWifi *self) { NMDeviceState state; @@ -1889,18 +1573,17 @@ supplicant_iface_bss_updated_cb (NMSupplicantInterface *iface, g_return_if_fail (object_path != NULL); g_return_if_fail (properties != NULL); - /* Ignore new APs when unavailable or unamnaged */ + /* Ignore new APs when unavailable or unmanaged */ state = nm_device_get_state (NM_DEVICE (self)); if (state <= NM_DEVICE_STATE_UNAVAILABLE) return; - /* Update the AP's last-seen property */ ap = get_ap_by_supplicant_path (self, object_path); - if (ap) - nm_ap_set_last_seen (ap, nm_utils_get_monotonic_timestamp_s ()); - - /* Remove outdated access points */ - schedule_scanlist_cull (self); + if (ap) { + nm_ap_dump (ap, "updated ", nm_device_get_iface (NM_DEVICE (self))); + nm_ap_update_from_properties (ap, object_path, properties); + schedule_ap_list_dump (self); + } } static void @@ -1908,28 +1591,28 @@ supplicant_iface_bss_removed_cb (NMSupplicantInterface *iface, const char *object_path, NMDeviceWifi *self) { + NMDeviceWifiPrivate *priv; NMAccessPoint *ap; g_return_if_fail (self != NULL); g_return_if_fail (object_path != NULL); + priv = NM_DEVICE_WIFI_GET_PRIVATE (self); ap = get_ap_by_supplicant_path (self, object_path); if (ap) { - gint32 now = nm_utils_get_monotonic_timestamp_s (); - gint32 last_seen = nm_ap_get_last_seen (ap); - - /* We don't know when the supplicant last saw the AP's beacons, - * it could be two minutes or it could be 2 seconds. Because the - * supplicant doesn't send property change notifications if the - * AP's other properties don't change, our last-seen time may be - * much older the supplicant's, and the AP would be immediately - * removed from the list on the next cleanup. So update the - * last-seen time to ensure the AP sticks around for at least - * one more periodic scan. - */ - nm_ap_set_last_seen (ap, MAX (last_seen, now - SCAN_INTERVAL_MAX)); - g_object_set_data (G_OBJECT (ap), WPAS_REMOVED_TAG, GUINT_TO_POINTER (TRUE)); -} + if (ap == priv->current_ap) { + /* The current AP cannot be removed (to prevent NM indicating that + * it is connected, but to nothing), but it must be removed later + * when the current AP is changed or cleared. Set 'fake' to + * indicate that this AP is now unknown to the supplicant. + */ + nm_ap_set_fake (ap, TRUE); + } else { + nm_ap_dump (ap, "removed ", nm_device_get_iface (NM_DEVICE (self))); + ap_add_remove (self, ACCESS_POINT_REMOVED, ap, TRUE); + schedule_ap_list_dump (self); + } + } } static void @@ -1937,15 +1620,8 @@ remove_supplicant_timeouts (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - if (priv->sup_timeout_id) { - g_source_remove (priv->sup_timeout_id); - priv->sup_timeout_id = 0; - } - - if (priv->link_timeout_id) { - g_source_remove (priv->link_timeout_id); - priv->link_timeout_id = 0; - } + nm_clear_g_source (&priv->sup_timeout_id); + nm_clear_g_source (&priv->link_timeout_id); } static void @@ -1970,17 +1646,19 @@ cleanup_supplicant_failures (NMDeviceWifi *self) static void wifi_secrets_cb (NMActRequest *req, - guint32 call_id, - NMConnection *connection, + NMActRequestGetSecretsCallId call_id, + NMSettingsConnection *connection, GError *error, gpointer user_data) { NMDevice *device = NM_DEVICE (user_data); NMDeviceWifi *self = NM_DEVICE_WIFI (device); - g_return_if_fail (req == nm_device_get_act_request (device)); + if (req != nm_device_get_act_request (device)) + return; + g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH); - g_return_if_fail (nm_act_request_get_connection (req) == connection); + g_return_if_fail (nm_act_request_get_settings_connection (req) == connection); if (error) { _LOGW (LOGD_WIFI, "%s", error->message); @@ -2015,23 +1693,7 @@ link_timeout_cb (gpointer user_data) if (nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED) return FALSE; - /* If the access point failed, and wasn't found by the supplicant when it - * attempted to reconnect, then it's probably out of range or turned off. - */ - if (priv->ssid_found == FALSE && priv->current_ap) { - NMAccessPoint *old_ap = g_object_ref (priv->current_ap); - - set_current_ap (self, NULL, TRUE); - - /* If it was an external entity and the supplicant doesn't know about - * it, remove it from the scan list. If it's still around, it'll get - * found in the next scan. - */ - if ( nm_ap_get_mode (old_ap) == NM_802_11_MODE_INFRA - && g_object_get_data (G_OBJECT (old_ap), WPAS_REMOVED_TAG)) - remove_access_point (self, old_ap); - g_object_unref (old_ap); - } + set_current_ap (self, NULL, TRUE); nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, @@ -2052,7 +1714,7 @@ need_new_8021x_secrets (NMDeviceWifi *self, g_assert (setting_name != NULL); - connection = nm_device_get_connection (NM_DEVICE (self)); + connection = nm_device_get_applied_connection (NM_DEVICE (self)); g_return_val_if_fail (connection != NULL, FALSE); /* 802.1x stuff only happens in the supplicant's ASSOCIATED state when it's @@ -2105,7 +1767,7 @@ need_new_wpa_psk (NMDeviceWifi *self, g_assert (setting_name != NULL); - connection = nm_device_get_connection (NM_DEVICE (self)); + connection = nm_device_get_applied_connection (NM_DEVICE (self)); g_return_val_if_fail (connection != NULL, FALSE); /* A bad PSK will cause the supplicant to disconnect during the 4-way handshake */ @@ -2133,7 +1795,6 @@ handle_8021x_or_psk_auth_fail (NMDeviceWifi *self, { NMDevice *device = NM_DEVICE (self); NMActRequest *req; - NMConnection *connection; const char *setting_name = NULL; gboolean handled = FALSE; @@ -2142,13 +1803,10 @@ handle_8021x_or_psk_auth_fail (NMDeviceWifi *self, req = nm_device_get_act_request (NM_DEVICE (self)); g_return_val_if_fail (req != NULL, FALSE); - connection = nm_act_request_get_connection (req); - g_assert (connection); - if ( need_new_8021x_secrets (self, old_state, &setting_name) || need_new_wpa_psk (self, old_state, &setting_name)) { - nm_connection_clear_secrets (connection); + nm_act_request_clear_secrets (req); _LOGI (LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) disconnected during association, asking for new key"); @@ -2236,7 +1894,7 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, NMSettingWireless *s_wifi; GBytes *ssid; - connection = nm_device_get_connection (NM_DEVICE (self)); + connection = nm_device_get_applied_connection (NM_DEVICE (self)); g_return_if_fail (connection); s_wifi = nm_connection_get_setting_wireless (connection); @@ -2253,7 +1911,7 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface, g_bytes_get_size (ssid)) : "(none)"); nm_device_activate_schedule_stage3_ip_config_start (device); } else if (devstate == NM_DEVICE_STATE_ACTIVATED) - periodic_update (self, NULL); + periodic_update (self); break; case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED: if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) { @@ -2359,7 +2017,53 @@ supplicant_iface_notify_scanning_cb (NMSupplicantInterface *iface, /* Run a quick update of current AP when coming out of a scan */ state = nm_device_get_state (NM_DEVICE (self)); if (!scanning && state == NM_DEVICE_STATE_ACTIVATED) - periodic_update (self, NULL); + periodic_update (self); +} + +static void +supplicant_iface_notify_current_bss (NMSupplicantInterface *iface, + GParamSpec *pspec, + NMDeviceWifi *self) +{ + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + const char *current_bss; + NMAccessPoint *new_ap = NULL; + + current_bss = nm_supplicant_interface_get_current_bss (iface); + if (current_bss) + new_ap = get_ap_by_supplicant_path (self, current_bss); + + if (new_ap != priv->current_ap) { + const char *new_bssid = NULL; + const GByteArray *new_ssid = NULL; + const char *old_bssid = NULL; + const GByteArray *old_ssid = NULL; + + /* Don't ever replace a "fake" current AP if we don't know about the + * supplicant's current BSS yet. It'll get replaced when we receive + * the current BSS's scan result. + */ + if (new_ap == NULL && nm_ap_get_fake (priv->current_ap)) + return; + + if (new_ap) { + new_bssid = nm_ap_get_address (new_ap); + new_ssid = nm_ap_get_ssid (new_ap); + } + + if (priv->current_ap) { + old_bssid = nm_ap_get_address (priv->current_ap); + old_ssid = nm_ap_get_ssid (priv->current_ap); + } + + _LOGD (LOGD_WIFI, "roamed from BSSID %s (%s) to %s (%s)", + old_bssid ? old_bssid : "(none)", + old_ssid ? nm_utils_escape_ssid (old_ssid->data, old_ssid->len) : "(none)", + new_bssid ? new_bssid : "(none)", + new_ssid ? nm_utils_escape_ssid (new_ssid->data, new_ssid->len) : "(none)"); + + set_current_ap (self, new_ap, TRUE); + } } static NMActStageReturn @@ -2369,7 +2073,7 @@ handle_auth_or_fail (NMDeviceWifi *self, { const char *setting_name; guint32 tries; - NMConnection *connection; + NMConnection *applied_connection; NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; g_return_val_if_fail (NM_IS_DEVICE_WIFI (self), NM_ACT_STAGE_RETURN_FAILURE); @@ -2379,17 +2083,16 @@ handle_auth_or_fail (NMDeviceWifi *self, g_assert (req); } - connection = nm_act_request_get_connection (req); - g_assert (connection); + applied_connection = nm_act_request_get_applied_connection (req); - tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (connection), WIRELESS_SECRETS_TRIES)); + tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (applied_connection), WIRELESS_SECRETS_TRIES)); if (tries > 3) return NM_ACT_STAGE_RETURN_FAILURE; nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); - nm_connection_clear_secrets (connection); - setting_name = nm_connection_need_secrets (connection, NULL); + nm_act_request_clear_secrets (req); + setting_name = nm_connection_need_secrets (applied_connection, NULL); if (setting_name) { NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; @@ -2397,7 +2100,7 @@ handle_auth_or_fail (NMDeviceWifi *self, flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; nm_act_request_get_secrets (req, setting_name, flags, NULL, wifi_secrets_cb, self); - g_object_set_data (G_OBJECT (connection), WIRELESS_SECRETS_TRIES, GUINT_TO_POINTER (++tries)); + g_object_set_data (G_OBJECT (applied_connection), WIRELESS_SECRETS_TRIES, GUINT_TO_POINTER (++tries)); ret = NM_ACT_STAGE_RETURN_POSTPONE; } else _LOGW (LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); @@ -2434,7 +2137,7 @@ supplicant_connection_timeout_cb (gpointer user_data) req = nm_device_get_act_request (device); g_assert (req); - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); g_assert (connection); if ( priv->mode == NM_802_11_MODE_ADHOC @@ -2468,7 +2171,7 @@ supplicant_connection_timeout_cb (gpointer user_data) * dialogs, just retry or fail, and if we never connect the user can * fix the password somewhere else. */ - if (nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (connection), ×tamp)) + if (nm_settings_connection_get_timestamp (nm_act_request_get_settings_connection (req), ×tamp)) new_secrets = !timestamp; if (handle_auth_or_fail (self, req, new_secrets) == NM_ACT_STAGE_RETURN_POSTPONE) @@ -2491,12 +2194,16 @@ supplicant_connection_timeout_cb (gpointer user_data) static NMSupplicantConfig * build_supplicant_config (NMDeviceWifi *self, NMConnection *connection, - guint32 fixed_freq) + guint32 fixed_freq, + GError **error) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMSupplicantConfig *config = NULL; NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_wireless_sec; + NMSupplicantFeature mac_randomization_support; + NMSettingMacRandomization mac_randomization_fallback; + gs_free char *svalue = NULL; g_return_val_if_fail (self != NULL, NULL); @@ -2504,19 +2211,29 @@ build_supplicant_config (NMDeviceWifi *self, g_return_val_if_fail (s_wireless != NULL, NULL); config = nm_supplicant_config_new (); - if (!config) - return NULL; /* Warn if AP mode may not be supported */ if ( g_strcmp0 (nm_setting_wireless_get_mode (s_wireless), NM_SETTING_WIRELESS_MODE_AP) == 0 - && nm_supplicant_interface_get_ap_support (priv->sup_iface) == AP_SUPPORT_UNKNOWN) { + && nm_supplicant_interface_get_ap_support (priv->sup_iface) == NM_SUPPLICANT_FEATURE_UNKNOWN) { _LOGW (LOGD_WIFI, "Supplicant may not support AP mode; connection may time out."); } + mac_randomization_support = nm_supplicant_interface_get_mac_randomization_support (priv->sup_iface); + svalue = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "wifi." NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION, + NM_DEVICE (self)); + mac_randomization_fallback = _nm_utils_ascii_str_to_int64 (svalue, 10, + NM_SETTING_MAC_RANDOMIZATION_DEFAULT, + NM_SETTING_MAC_RANDOMIZATION_ALWAYS, + NM_SETTING_MAC_RANDOMIZATION_DEFAULT); + if (!nm_supplicant_config_add_setting_wireless (config, s_wireless, - fixed_freq)) { - _LOGE (LOGD_WIFI, "Couldn't add 802-11-wireless setting to supplicant config."); + fixed_freq, + mac_randomization_support, + mac_randomization_fallback, + error)) { + g_prefix_error (error, "802-11-wireless: "); goto error; } @@ -2533,13 +2250,14 @@ build_supplicant_config (NMDeviceWifi *self, s_wireless_sec, s_8021x, con_uuid, - mtu)) { - _LOGE (LOGD_WIFI, "Couldn't add 802-11-wireless-security setting to supplicant config."); + mtu, + error)) { + g_prefix_error (error, "802-11-wireless-security: "); goto error; } } else { - if (!nm_supplicant_config_add_no_security (config)) { - _LOGE (LOGD_WIFI, "Couldn't add unsecured option to supplicant config."); + if (!nm_supplicant_config_add_no_security (config, error)) { + g_prefix_error (error, "unsecured-option: "); goto error; } } @@ -2564,7 +2282,6 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) NMConnection *connection; NMSettingWireless *s_wireless; const char *cloned_mac; - GSList *iter; const char *mode; const char *ap_path; @@ -2575,7 +2292,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) req = nm_device_get_act_request (NM_DEVICE (self)); g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE); - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); g_return_val_if_fail (connection != NULL, NM_ACT_STAGE_RETURN_FAILURE); s_wireless = nm_connection_get_setting_wireless (connection); @@ -2611,25 +2328,17 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) /* AP mode never uses a specific object or existing scanned AP */ if (priv->mode != NM_802_11_MODE_AP) { - ap_path = nm_active_connection_get_specific_object (NM_ACTIVE_CONNECTION (req)); ap = ap_path ? get_ap_by_path (self, ap_path) : NULL; if (ap) goto done; - /* Find a compatible AP in the scan list */ - for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) { - NMAccessPoint *candidate = NM_AP (iter->data); - - if (nm_ap_check_compatible (candidate, connection)) { - ap = candidate; - break; - } - } + ap = find_first_compatible_ap (self, connection, FALSE); } if (ap) { - nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req), nm_ap_get_dbus_path (ap)); + nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req), + nm_exported_object_get_path (NM_EXPORTED_OBJECT (ap))); goto done; } @@ -2642,18 +2351,15 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) ap = nm_ap_new_fake_from_connection (connection); g_return_val_if_fail (ap != NULL, NM_ACT_STAGE_RETURN_FAILURE); - if (nm_ap_get_mode (ap) == NM_802_11_MODE_INFRA) - nm_ap_set_broadcast (ap, FALSE); - else if (nm_ap_is_hotspot (ap)) + if (nm_ap_is_hotspot (ap)) nm_ap_set_address (ap, nm_device_get_hw_address (device)); - priv->ap_list = g_slist_prepend (priv->ap_list, ap); - nm_ap_export_to_dbus (ap); g_object_freeze_notify (G_OBJECT (self)); - set_current_ap (self, ap, FALSE); - emit_ap_added_removed (self, ACCESS_POINT_ADDED, ap, TRUE); + ap_add_remove (self, ACCESS_POINT_ADDED, ap, TRUE); g_object_thaw_notify (G_OBJECT (self)); - nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req), nm_ap_get_dbus_path (ap)); + set_current_ap (self, ap, FALSE); + nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req), + nm_exported_object_get_path (NM_EXPORTED_OBJECT (ap))); return NM_ACT_STAGE_RETURN_SUCCESS; done: @@ -2699,6 +2405,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) NMConnection *connection; const char *setting_name; NMSettingWireless *s_wireless; + GError *error = NULL; g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); @@ -2713,7 +2420,7 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) goto out; } - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); g_assert (connection); s_wireless = nm_connection_get_setting_wireless (connection); @@ -2752,11 +2459,19 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) if ((nm_ap_get_mode (ap) == NM_802_11_MODE_ADHOC) || nm_ap_is_hotspot (ap)) ensure_hotspot_frequency (self, s_wireless, ap); + if (nm_ap_get_mode (ap) == NM_802_11_MODE_INFRA) { + nm_platform_wifi_set_powersave (NM_PLATFORM_GET, + nm_device_get_ifindex (device), + nm_setting_wireless_get_powersave (s_wireless)); + } + /* Build up the supplicant configuration */ - config = build_supplicant_config (self, connection, nm_ap_get_freq (ap)); + config = build_supplicant_config (self, connection, nm_ap_get_freq (ap), &error); if (config == NULL) { _LOGE (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) couldn't build wireless configuration."); + "Activation: (wifi) couldn't build wireless configuration: %s", + error ? error->message : ""); + g_clear_error (&error); *reason = NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED; goto out; } @@ -2767,9 +2482,11 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) G_CALLBACK (supplicant_iface_connection_error_cb), self); - if (!nm_supplicant_interface_set_config (priv->sup_iface, config)) { + if (!nm_supplicant_interface_set_config (priv->sup_iface, config, &error)) { _LOGE (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) couldn't send wireless configuration to the supplicant."); + "Activation: (wifi) couldn't send wireless configuration to the supplicant: %s", + error ? error->message : ""); + g_clear_error (&error); *reason = NM_DEVICE_STATE_REASON_SUPPLICANT_CONFIG_FAILED; goto out; } @@ -2805,7 +2522,7 @@ act_stage3_ip4_config_start (NMDevice *device, NMSettingIPConfig *s_ip4; const char *method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; - connection = nm_device_get_connection (device); + connection = nm_device_get_applied_connection (device); g_assert (connection); s_ip4 = nm_connection_get_setting_ip4_config (connection); if (s_ip4) @@ -2827,7 +2544,7 @@ act_stage3_ip6_config_start (NMDevice *device, NMSettingIPConfig *s_ip6; const char *method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; - connection = nm_device_get_connection (device); + connection = nm_device_get_applied_connection (device); g_assert (connection); s_ip6 = nm_connection_get_setting_ip6_config (connection); if (s_ip6) @@ -2848,7 +2565,7 @@ ip4_config_pre_commit (NMDevice *device, NMIP4Config *config) NMSettingWireless *s_wifi; guint32 mtu; - connection = nm_device_get_connection (device); + connection = nm_device_get_applied_connection (device); g_assert (connection); s_wifi = nm_connection_get_setting_wireless (connection); g_assert (s_wifi); @@ -2935,7 +2652,7 @@ act_stage4_ip4_config_timeout (NMDevice *device, NMDeviceStateReason *reason) gboolean may_fail = FALSE, chain_up = FALSE; NMActStageReturn ret; - connection = nm_device_get_connection (device); + connection = nm_device_get_applied_connection (device); g_assert (connection); s_ip4 = nm_connection_get_setting_ip4_config (connection); @@ -2956,7 +2673,7 @@ act_stage4_ip6_config_timeout (NMDevice *device, NMDeviceStateReason *reason) gboolean may_fail = FALSE, chain_up = FALSE; NMActStageReturn ret; - connection = nm_device_get_connection (device); + connection = nm_device_get_applied_connection (device); g_assert (connection); s_ip6 = nm_connection_get_setting_ip6_config (connection); @@ -2975,78 +2692,53 @@ activation_success_handler (NMDevice *device) NMDeviceWifi *self = NM_DEVICE_WIFI (device); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); int ifindex = nm_device_get_ifindex (device); - NMAccessPoint *ap; - guint8 bssid[ETH_ALEN] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; - NMAccessPoint *tmp_ap = NULL; NMActRequest *req; - NMConnection *connection; + NMConnection *applied_connection; req = nm_device_get_act_request (device); g_assert (req); - connection = nm_act_request_get_connection (req); - g_assert (connection); + applied_connection = nm_act_request_get_applied_connection (req); /* Clear any critical protocol notification in the wifi stack */ nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, ifindex, FALSE); /* Clear wireless secrets tries on success */ - g_object_set_data (G_OBJECT (connection), WIRELESS_SECRETS_TRIES, NULL); - - ap = priv->current_ap; - - /* If the AP isn't fake, it was found in the scan list and all its - * details are known. - */ - if (!ap || !nm_ap_get_fake (ap)){ - ap = NULL; - goto done; - } + g_object_set_data (G_OBJECT (applied_connection), WIRELESS_SECRETS_TRIES, NULL); - /* If the activate AP was fake, it probably won't have a BSSID at all. - * But if activation was successful, the card will know the BSSID. Grab - * the BSSID off the card and fill in the BSSID of the activation AP. + /* There should always be a current AP, either a fake one because we haven't + * seen a scan result for the activated AP yet, or a real one from the + * supplicant's scan list. */ - nm_platform_wifi_get_bssid (NM_PLATFORM_GET, ifindex, bssid); - if (!nm_ap_get_address (ap)) { - char *bssid_str = nm_utils_hwaddr_ntoa (bssid, ETH_ALEN); - nm_ap_set_address (ap, bssid_str); - g_free (bssid_str); - } - if (!nm_ap_get_freq (ap)) - nm_ap_set_freq (ap, nm_platform_wifi_get_frequency (NM_PLATFORM_GET, ifindex)); - if (!nm_ap_get_max_bitrate (ap)) - nm_ap_set_max_bitrate (ap, nm_platform_wifi_get_rate (NM_PLATFORM_GET, ifindex)); - - tmp_ap = find_active_ap (self, ap, TRUE); - if (tmp_ap) { - const GByteArray *ssid = nm_ap_get_ssid (tmp_ap); - - /* Found a better match in the scan list than the fake AP. Use it - * instead. - */ - - /* If the better match was a hidden AP, update its SSID */ - if (!ssid || nm_utils_is_empty_ssid (ssid->data, ssid->len)) { - ssid = nm_ap_get_ssid (ap); - nm_ap_set_ssid (tmp_ap, ssid->data, ssid->len); + g_warn_if_fail (priv->current_ap); + if (priv->current_ap) { + if (nm_ap_get_fake (priv->current_ap)) { + /* If the activation AP hasn't been seen by the supplicant in a scan + * yet, it will be "fake". This usually happens for Ad-Hoc and + * AP-mode connections. Fill in the details from the device itself + * until the supplicant sends the scan result. + */ + if (!nm_ap_get_address (priv->current_ap)) { + guint8 bssid[ETH_ALEN] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + gs_free char *bssid_str = NULL; + + if ( nm_platform_wifi_get_bssid (NM_PLATFORM_GET, ifindex, bssid) + && nm_ethernet_address_is_valid (bssid, ETH_ALEN)) { + bssid_str = nm_utils_hwaddr_ntoa (bssid, ETH_ALEN); + nm_ap_set_address (priv->current_ap, bssid_str); + } + } + if (!nm_ap_get_freq (priv->current_ap)) + nm_ap_set_freq (priv->current_ap, nm_platform_wifi_get_frequency (NM_PLATFORM_GET, ifindex)); + if (!nm_ap_get_max_bitrate (priv->current_ap)) + nm_ap_set_max_bitrate (priv->current_ap, nm_platform_wifi_get_rate (NM_PLATFORM_GET, ifindex)); } nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req), - nm_ap_get_dbus_path (tmp_ap)); + nm_exported_object_get_path (NM_EXPORTED_OBJECT (priv->current_ap))); } -done: - periodic_update (self, ap); - - /* ap might be already unrefed, because it was a fake_ap. But we don't touch it... */ - if (tmp_ap && ap == priv->current_ap) { - /* Strange, we would expect periodic_update() to find a better AP - * then the fake one and reset it. Reset the fake current_ap to NULL - * now, which will remove the fake ap. - **/ - set_current_ap (self, NULL, TRUE); - } + periodic_update (self); update_seen_bssids_cache (self, priv->current_ap); @@ -3057,13 +2749,13 @@ done: static void activation_failure_handler (NMDevice *device) { - NMConnection *connection; + NMConnection *applied_connection; - connection = nm_device_get_connection (device); - g_assert (connection); + applied_connection = nm_device_get_applied_connection (device); + g_assert (applied_connection); /* Clear wireless secrets tries on failure */ - g_object_set_data (G_OBJECT (connection), WIRELESS_SECRETS_TRIES, NULL); + g_object_set_data (G_OBJECT (applied_connection), WIRELESS_SECRETS_TRIES, NULL); /* Clear any critical protocol notification in the wifi stack */ nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, nm_device_get_ifindex (device), FALSE); @@ -3086,10 +2778,7 @@ device_state_changed (NMDevice *device, if (priv->sup_iface) supplicant_interface_release (self); - if (priv->periodic_source_id) { - g_source_remove (priv->periodic_source_id); - priv->periodic_source_id = 0; - } + nm_clear_g_source (&priv->periodic_source_id); cleanup_association_attempt (self, TRUE); cleanup_supplicant_failures (self); @@ -3196,22 +2885,25 @@ set_enabled (NMDevice *device, gboolean enabled) /********************************************************************/ NMDevice * -nm_device_wifi_new (NMPlatformLink *platform_device) +nm_device_wifi_new (const char *iface, NMDeviceWifiCapabilities capabilities) { - g_return_val_if_fail (platform_device != NULL, NULL); - - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_WIFI, - NM_DEVICE_PLATFORM_DEVICE, platform_device, - NM_DEVICE_TYPE_DESC, "802.11 WiFi", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_WIFI, - NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WLAN, - NULL); + return g_object_new (NM_TYPE_DEVICE_WIFI, + NM_DEVICE_IFACE, iface, + NM_DEVICE_TYPE_DESC, "802.11 WiFi", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_WIFI, + NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_WIFI, + NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WLAN, + NM_DEVICE_WIFI_CAPABILITIES, (guint) capabilities, + NULL); } static void nm_device_wifi_init (NMDeviceWifi *self) { - NM_DEVICE_WIFI_GET_PRIVATE (self)->mode = NM_802_11_MODE_INFRA; + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + + priv->mode = NM_802_11_MODE_INFRA; + priv->aps = g_hash_table_new (g_str_hash, g_str_equal); } static void @@ -3220,17 +2912,7 @@ dispose (GObject *object) NMDeviceWifi *self = NM_DEVICE_WIFI (object); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - if (priv->disposed) { - G_OBJECT_CLASS (nm_device_wifi_parent_class)->dispose (object); - return; - } - - priv->disposed = TRUE; - - if (priv->periodic_source_id) { - g_source_remove (priv->periodic_source_id); - priv->periodic_source_id = 0; - } + nm_clear_g_source (&priv->periodic_source_id); cleanup_association_attempt (self, TRUE); supplicant_interface_release (self); @@ -3246,6 +2928,13 @@ dispose (GObject *object) static void finalize (GObject *object) { + NMDeviceWifi *self = NM_DEVICE_WIFI (object); + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); + + nm_assert (g_hash_table_size (priv->aps) == 0); + + g_hash_table_unref (priv->aps); + G_OBJECT_CLASS (nm_device_wifi_parent_class)->finalize (object); } @@ -3255,8 +2944,9 @@ get_property (GObject *object, guint prop_id, { NMDeviceWifi *device = NM_DEVICE_WIFI (object); NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device); + GHashTableIter iter; + const char *dbus_path; GPtrArray *array; - GSList *iter; switch (prop_id) { case PROP_PERM_HW_ADDRESS: @@ -3272,16 +2962,15 @@ get_property (GObject *object, guint prop_id, g_value_set_uint (value, priv->capabilities); break; case PROP_ACCESS_POINTS: - array = g_ptr_array_sized_new (4); - for (iter = priv->ap_list; iter; iter = g_slist_next (iter)) - g_ptr_array_add (array, g_strdup (nm_ap_get_dbus_path (NM_AP (iter->data)))); - g_value_take_boxed (value, array); + array = g_ptr_array_sized_new (g_hash_table_size (priv->aps) + 1); + g_hash_table_iter_init (&iter, priv->aps); + while (g_hash_table_iter_next (&iter, (gpointer) &dbus_path, NULL)) + g_ptr_array_add (array, g_strdup (dbus_path)); + g_ptr_array_add (array, NULL); + g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE)); break; case PROP_ACTIVE_ACCESS_POINT: - if (priv->current_ap) - g_value_set_boxed (value, nm_ap_get_dbus_path (priv->current_ap)); - else - g_value_set_boxed (value, "/"); + nm_utils_g_value_set_object_path (value, priv->current_ap); break; case PROP_SCANNING: g_value_set_boolean (value, nm_supplicant_interface_get_scanning (priv->sup_iface)); @@ -3296,7 +2985,14 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { + NMDeviceWifi *device = NM_DEVICE_WIFI (object); + NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (device); + switch (prop_id) { + case PROP_CAPABILITIES: + /* construct-only */ + priv->capabilities = g_value_get_uint (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -3312,12 +3008,15 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) g_type_class_add_private (object_class, sizeof (NMDeviceWifiPrivate)); - object_class->constructor = constructor; + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_WIRELESS_SETTING_NAME, NM_LINK_TYPE_WIFI) + + object_class->constructed = constructed; object_class->get_property = get_property; object_class->set_property = set_property; object_class->dispose = dispose; object_class->finalize = finalize; + parent_class->realize_start_notify = realize_start_notify; parent_class->bring_up = bring_up; parent_class->can_auto_connect = can_auto_connect; parent_class->is_available = is_available; @@ -3366,22 +3065,23 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) g_object_class_install_property (object_class, PROP_ACCESS_POINTS, g_param_spec_boxed (NM_DEVICE_WIFI_ACCESS_POINTS, "", "", - DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, + G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_ACTIVE_ACCESS_POINT, - g_param_spec_boxed (NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_DEVICE_WIFI_ACTIVE_ACCESS_POINT, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_CAPABILITIES, g_param_spec_uint (NM_DEVICE_WIFI_CAPABILITIES, "", "", 0, G_MAXUINT32, NM_WIFI_DEVICE_CAP_NONE, - G_PARAM_READABLE | + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property @@ -3399,7 +3099,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) G_STRUCT_OFFSET (NMDeviceWifiClass, access_point_added), NULL, NULL, NULL, G_TYPE_NONE, 1, - G_TYPE_OBJECT); + NM_TYPE_AP); signals[ACCESS_POINT_REMOVED] = g_signal_new ("access-point-removed", @@ -3408,7 +3108,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) 0, NULL, NULL, NULL, G_TYPE_NONE, 1, - G_TYPE_OBJECT); + NM_TYPE_AP); signals[SCANNING_ALLOWED] = g_signal_new ("scanning-allowed", @@ -3418,9 +3118,12 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) scanning_allowed_accumulator, NULL, NULL, G_TYPE_BOOLEAN, 0); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_wifi_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_WIFI_SKELETON, + "GetAccessPoints", impl_device_wifi_get_access_points, + "GetAllAccessPoints", impl_device_wifi_get_all_access_points, + "RequestScan", impl_device_wifi_request_scan, + NULL); } diff --git a/src/devices/wifi/nm-device-wifi.h b/src/devices/wifi/nm-device-wifi.h index bcba91da..7e0d06f5 100644 --- a/src/devices/wifi/nm-device-wifi.h +++ b/src/devices/wifi/nm-device-wifi.h @@ -22,8 +22,6 @@ #ifndef __NETWORKMANAGER_DEVICE_WIFI_H__ #define __NETWORKMANAGER_DEVICE_WIFI_H__ -#include - #include "nm-device.h" #include "nm-wifi-ap.h" @@ -75,7 +73,7 @@ struct _NMDeviceWifiClass GType nm_device_wifi_get_type (void); -NMDevice *nm_device_wifi_new (NMPlatformLink *platform_device); +NMDevice * nm_device_wifi_new (const char *iface, NMDeviceWifiCapabilities capabilities); G_END_DECLS diff --git a/src/devices/wifi/nm-wifi-ap-utils.c b/src/devices/wifi/nm-wifi-ap-utils.c index 1a772fb7..d7916aa0 100644 --- a/src/devices/wifi/nm-wifi-ap-utils.c +++ b/src/devices/wifi/nm-wifi-ap-utils.c @@ -23,8 +23,7 @@ #include #include -#include - +#include "nm-default.h" #include "nm-wifi-ap-utils.h" #include "nm-utils.h" diff --git a/src/devices/wifi/nm-wifi-ap.c b/src/devices/wifi/nm-wifi-ap.c index 72430021..771d6704 100644 --- a/src/devices/wifi/nm-wifi-ap.c +++ b/src/devices/wifi/nm-wifi-ap.c @@ -24,32 +24,29 @@ #include #include +#include "nm-default.h" #include "nm-wifi-ap.h" #include "nm-wifi-ap-utils.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" -#include "nm-logging.h" -#include "nm-dbus-manager.h" #include "nm-core-internal.h" #include "nm-setting-wireless.h" -#include "nm-glib-compat.h" -#include "nm-access-point-glue.h" +#include "nmdbus-access-point.h" /* * Encapsulates Access Point information */ typedef struct { - char *dbus_path; char *supplicant_path; /* D-Bus object path of this AP from wpa_supplicant */ /* Scanned or cached values */ GByteArray * ssid; char * address; NM80211Mode mode; - gint8 strength; + guint8 strength; guint32 freq; /* Frequency in MHz; ie 2412 (== 2.412 GHz) */ guint32 max_bitrate;/* Maximum bitrate of the AP in Kbit/s (ie 54000 Kb/s == 54Mbit/s) */ @@ -60,13 +57,12 @@ typedef struct /* Non-scanned attributes */ gboolean fake; /* Whether or not the AP is from a scan */ gboolean hotspot; /* Whether the AP is a local device's hotspot network */ - gboolean broadcast; /* Whether or not the AP is broadcasting (hidden) */ gint32 last_seen; /* Timestamp when the AP was seen lastly (obtained via nm_utils_get_monotonic_timestamp_s()) */ } NMAccessPointPrivate; #define NM_AP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AP, NMAccessPointPrivate)) -G_DEFINE_TYPE (NMAccessPoint, nm_ap, G_TYPE_OBJECT) +G_DEFINE_TYPE (NMAccessPoint, nm_ap, NM_TYPE_EXPORTED_OBJECT) enum { PROP_0, @@ -83,313 +79,313 @@ enum { LAST_PROP }; -static void -nm_ap_init (NMAccessPoint *ap) +/*****************************************************************/ + +const char * +nm_ap_get_supplicant_path (NMAccessPoint *ap) { - NMAccessPointPrivate *priv = NM_AP_GET_PRIVATE (ap); + g_return_val_if_fail (NM_IS_AP (ap), NULL); - priv->dbus_path = NULL; - priv->mode = NM_802_11_MODE_INFRA; - priv->flags = NM_802_11_AP_FLAGS_NONE; - priv->wpa_flags = NM_802_11_AP_SEC_NONE; - priv->rsn_flags = NM_802_11_AP_SEC_NONE; - priv->broadcast = TRUE; + return NM_AP_GET_PRIVATE (ap)->supplicant_path; } -static void -finalize (GObject *object) +guint32 +nm_ap_get_id (NMAccessPoint *ap) { - NMAccessPointPrivate *priv = NM_AP_GET_PRIVATE (object); + g_return_val_if_fail (NM_IS_AP (ap), 0); + g_return_val_if_fail (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (ap)), 0); - g_free (priv->dbus_path); - g_free (priv->supplicant_path); - if (priv->ssid) + return atoi (strrchr (nm_exported_object_get_path (NM_EXPORTED_OBJECT (ap)), '/') + 1); +} + +const GByteArray * nm_ap_get_ssid (const NMAccessPoint *ap) +{ + g_return_val_if_fail (NM_IS_AP (ap), NULL); + + return NM_AP_GET_PRIVATE (ap)->ssid; +} + +void +nm_ap_set_ssid (NMAccessPoint *ap, const guint8 *ssid, gsize len) +{ + NMAccessPointPrivate *priv; + + g_return_if_fail (NM_IS_AP (ap)); + g_return_if_fail (ssid == NULL || len > 0); + + priv = NM_AP_GET_PRIVATE (ap); + + /* same SSID */ + if ((ssid && priv->ssid) && (len == priv->ssid->len)) { + if (!memcmp (ssid, priv->ssid->data, len)) + return; + } + + if (priv->ssid) { g_byte_array_free (priv->ssid, TRUE); - g_free (priv->address); + priv->ssid = NULL; + } - G_OBJECT_CLASS (nm_ap_parent_class)->finalize (object); + if (ssid) { + priv->ssid = g_byte_array_new (); + g_byte_array_append (priv->ssid, ssid, len); + } + + g_object_notify (G_OBJECT (ap), NM_AP_SSID); } static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) +nm_ap_set_flags (NMAccessPoint *ap, NM80211ApFlags flags) { - NMAccessPoint *ap = NM_AP (object); - GByteArray *ssid; + NMAccessPointPrivate *priv; - switch (prop_id) { - case PROP_FLAGS: - nm_ap_set_flags (ap, g_value_get_uint (value)); - break; - case PROP_WPA_FLAGS: - nm_ap_set_wpa_flags (ap, g_value_get_uint (value)); - break; - case PROP_RSN_FLAGS: - nm_ap_set_rsn_flags (ap, g_value_get_uint (value)); - break; - case PROP_SSID: - ssid = g_value_get_boxed (value); - if (ssid) - nm_ap_set_ssid (ap, ssid->data, ssid->len); - else - nm_ap_set_ssid (ap, NULL, 0); - break; - case PROP_FREQUENCY: - nm_ap_set_freq (ap, g_value_get_uint (value)); - break; - case PROP_MODE: - nm_ap_set_mode (ap, g_value_get_uint (value)); - break; - case PROP_MAX_BITRATE: - nm_ap_set_max_bitrate (ap, g_value_get_uint (value)); - break; - case PROP_STRENGTH: - nm_ap_set_strength (ap, g_value_get_schar (value)); - break; - case PROP_HW_ADDRESS: - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + g_return_if_fail (NM_IS_AP (ap)); + + priv = NM_AP_GET_PRIVATE (ap); + + if (priv->flags != flags) { + priv->flags = flags; + g_object_notify (G_OBJECT (ap), NM_AP_FLAGS); } } static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) +nm_ap_set_wpa_flags (NMAccessPoint *ap, NM80211ApSecurityFlags flags) { - NMAccessPointPrivate *priv = NM_AP_GET_PRIVATE (object); - GArray * ssid; - int len; - int i; + NMAccessPointPrivate *priv; - switch (prop_id) { - case PROP_FLAGS: - g_value_set_uint (value, priv->flags); - break; - case PROP_WPA_FLAGS: - g_value_set_uint (value, priv->wpa_flags); - break; - case PROP_RSN_FLAGS: - g_value_set_uint (value, priv->rsn_flags); - break; - case PROP_SSID: - len = priv->ssid ? priv->ssid->len : 0; - ssid = g_array_sized_new (FALSE, TRUE, sizeof (unsigned char), len); - for (i = 0; i < len; i++) - g_array_append_val (ssid, priv->ssid->data[i]); - g_value_set_boxed (value, ssid); - g_array_free (ssid, TRUE); - break; - case PROP_FREQUENCY: - g_value_set_uint (value, priv->freq); - break; - case PROP_HW_ADDRESS: - g_value_set_string (value, priv->address); - break; - case PROP_MODE: - g_value_set_uint (value, priv->mode); - break; - case PROP_MAX_BITRATE: - g_value_set_uint (value, priv->max_bitrate); - break; - case PROP_STRENGTH: - g_value_set_schar (value, priv->strength); - break; - case PROP_LAST_SEEN: - g_value_set_int (value, - priv->last_seen > 0 - ? (gint) nm_utils_monotonic_timestamp_as_boottime (priv->last_seen, NM_UTILS_NS_PER_SECOND) - : -1); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; + g_return_if_fail (NM_IS_AP (ap)); + + priv = NM_AP_GET_PRIVATE (ap); + if (priv->wpa_flags != flags) { + priv->wpa_flags = flags; + g_object_notify (G_OBJECT (ap), NM_AP_WPA_FLAGS); } } static void -nm_ap_class_init (NMAccessPointClass *ap_class) +nm_ap_set_rsn_flags (NMAccessPoint *ap, NM80211ApSecurityFlags flags) { - GObjectClass *object_class = G_OBJECT_CLASS (ap_class); - const NM80211ApSecurityFlags all_sec_flags = NM_802_11_AP_SEC_NONE - | NM_802_11_AP_SEC_PAIR_WEP40 - | NM_802_11_AP_SEC_PAIR_WEP104 - | NM_802_11_AP_SEC_PAIR_TKIP - | NM_802_11_AP_SEC_PAIR_CCMP - | NM_802_11_AP_SEC_GROUP_WEP40 - | NM_802_11_AP_SEC_GROUP_WEP104 - | NM_802_11_AP_SEC_GROUP_TKIP - | NM_802_11_AP_SEC_GROUP_CCMP - | NM_802_11_AP_SEC_KEY_MGMT_PSK - | NM_802_11_AP_SEC_KEY_MGMT_802_1X; - - g_type_class_add_private (ap_class, sizeof (NMAccessPointPrivate)); + NMAccessPointPrivate *priv; - /* virtual methods */ - object_class->set_property = set_property; - object_class->get_property = get_property; - object_class->finalize = finalize; + g_return_if_fail (NM_IS_AP (ap)); - /* properties */ - g_object_class_install_property - (object_class, PROP_FLAGS, - g_param_spec_uint (NM_AP_FLAGS, "", "", - NM_802_11_AP_FLAGS_NONE, - NM_802_11_AP_FLAGS_PRIVACY, - NM_802_11_AP_FLAGS_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); + priv = NM_AP_GET_PRIVATE (ap); + if (priv->rsn_flags != flags) { + priv->rsn_flags = flags; + g_object_notify (G_OBJECT (ap), NM_AP_RSN_FLAGS); + } +} - g_object_class_install_property - (object_class, PROP_WPA_FLAGS, - g_param_spec_uint (NM_AP_WPA_FLAGS, "", "", - NM_802_11_AP_SEC_NONE, - all_sec_flags, - NM_802_11_AP_SEC_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); +const char * +nm_ap_get_address (const NMAccessPoint *ap) +{ + g_return_val_if_fail (NM_IS_AP (ap), NULL); - g_object_class_install_property - (object_class, PROP_RSN_FLAGS, - g_param_spec_uint (NM_AP_RSN_FLAGS, "", "", - NM_802_11_AP_SEC_NONE, - all_sec_flags, - NM_802_11_AP_SEC_NONE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); + return NM_AP_GET_PRIVATE (ap)->address; +} - g_object_class_install_property - (object_class, PROP_SSID, - g_param_spec_boxed (NM_AP_SSID, "", "", - DBUS_TYPE_G_UCHAR_ARRAY, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); +void +nm_ap_set_address (NMAccessPoint *ap, const char *addr) +{ + NMAccessPointPrivate *priv; - g_object_class_install_property - (object_class, PROP_FREQUENCY, - g_param_spec_uint (NM_AP_FREQUENCY, "", "", - 0, 10000, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); + g_return_if_fail (NM_IS_AP (ap)); + g_return_if_fail (addr != NULL); + g_return_if_fail (nm_utils_hwaddr_valid (addr, ETH_ALEN)); - g_object_class_install_property - (object_class, PROP_HW_ADDRESS, - g_param_spec_string (NM_AP_HW_ADDRESS, "", "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_MODE, - g_param_spec_uint (NM_AP_MODE, "", "", - NM_802_11_MODE_ADHOC, NM_802_11_MODE_INFRA, NM_802_11_MODE_INFRA, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); + priv = NM_AP_GET_PRIVATE (ap); - g_object_class_install_property - (object_class, PROP_MAX_BITRATE, - g_param_spec_uint (NM_AP_MAX_BITRATE, "", "", - 0, G_MAXUINT16, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); + if (!priv->address || !nm_utils_hwaddr_matches (addr, -1, priv->address, -1)) { + g_free (priv->address); + priv->address = g_strdup (addr); + g_object_notify (G_OBJECT (ap), NM_AP_HW_ADDRESS); + } +} - g_object_class_install_property - (object_class, PROP_STRENGTH, - g_param_spec_char (NM_AP_STRENGTH, "", "", - G_MININT8, G_MAXINT8, 0, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); +NM80211Mode +nm_ap_get_mode (NMAccessPoint *ap) +{ + g_return_val_if_fail (NM_IS_AP (ap), NM_802_11_MODE_UNKNOWN); - g_object_class_install_property - (object_class, PROP_LAST_SEEN, - g_param_spec_int (NM_AP_LAST_SEEN, "", "", - -1, G_MAXINT, -1, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (ap_class), - &dbus_glib_nm_access_point_object_info); + return NM_AP_GET_PRIVATE (ap)->mode; } -void -nm_ap_export_to_dbus (NMAccessPoint *ap) +static void +nm_ap_set_mode (NMAccessPoint *ap, const NM80211Mode mode) { NMAccessPointPrivate *priv; - static guint32 counter = 0; g_return_if_fail (NM_IS_AP (ap)); + g_return_if_fail ( mode == NM_802_11_MODE_ADHOC + || mode == NM_802_11_MODE_INFRA); priv = NM_AP_GET_PRIVATE (ap); - if (priv->dbus_path) { - nm_log_err (LOGD_CORE, "Tried to export AP %s twice.", priv->dbus_path); - return; + if (priv->mode != mode) { + priv->mode = mode; + g_object_notify (G_OBJECT (ap), NM_AP_MODE); } +} + +gboolean +nm_ap_is_hotspot (NMAccessPoint *ap) +{ + g_return_val_if_fail (NM_IS_AP (ap), FALSE); - priv->dbus_path = g_strdup_printf (NM_DBUS_PATH_ACCESS_POINT "/%d", counter++); - nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->dbus_path, ap); + return NM_AP_GET_PRIVATE (ap)->hotspot; } -/* - * nm_ap_new - * - * Create a new, blank user access point info structure - * - */ -static NMAccessPoint * -nm_ap_new (void) +gint8 +nm_ap_get_strength (NMAccessPoint *ap) { - return (NMAccessPoint *) g_object_new (NM_TYPE_AP, NULL); + g_return_val_if_fail (NM_IS_AP (ap), 0); + + return NM_AP_GET_PRIVATE (ap)->strength; } -static NM80211ApSecurityFlags -security_from_vardict (GVariant *security) +void +nm_ap_set_strength (NMAccessPoint *ap, const gint8 strength) { - NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE; - const char **array, *tmp; + NMAccessPointPrivate *priv; - g_return_val_if_fail (g_variant_is_of_type (security, G_VARIANT_TYPE_VARDICT), NM_802_11_AP_SEC_NONE); + g_return_if_fail (NM_IS_AP (ap)); - if (g_variant_lookup (security, "KeyMgmt", "^a&s", &array)) { - if (_nm_utils_string_in_list ("wpa-psk", array)) - flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK; - if (_nm_utils_string_in_list ("wpa-eap", array)) - flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X; - g_free (array); - } + priv = NM_AP_GET_PRIVATE (ap); - if (g_variant_lookup (security, "Pairwise", "^a&s", &array)) { - if (_nm_utils_string_in_list ("tkip", array)) - flags |= NM_802_11_AP_SEC_PAIR_TKIP; - if (_nm_utils_string_in_list ("ccmp", array)) - flags |= NM_802_11_AP_SEC_PAIR_CCMP; - g_free (array); + if (priv->strength != strength) { + priv->strength = strength; + g_object_notify (G_OBJECT (ap), NM_AP_STRENGTH); } +} - if (g_variant_lookup (security, "Group", "&s", &tmp)) { - if (strcmp (tmp, "wep40") == 0) - flags |= NM_802_11_AP_SEC_GROUP_WEP40; - if (strcmp (tmp, "wep104") == 0) - flags |= NM_802_11_AP_SEC_GROUP_WEP104; - if (strcmp (tmp, "tkip") == 0) - flags |= NM_802_11_AP_SEC_GROUP_TKIP; - if (strcmp (tmp, "ccmp") == 0) - flags |= NM_802_11_AP_SEC_GROUP_CCMP; - } +guint32 +nm_ap_get_freq (NMAccessPoint *ap) +{ + g_return_val_if_fail (NM_IS_AP (ap), 0); - return flags; + return NM_AP_GET_PRIVATE (ap)->freq; } -NMAccessPoint * -nm_ap_new_from_properties (const char *supplicant_path, GVariant *properties) +void +nm_ap_set_freq (NMAccessPoint *ap, + const guint32 freq) { - const char bad_bssid1[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - const char bad_bssid2[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - const char *addr; + NMAccessPointPrivate *priv; + + g_return_if_fail (NM_IS_AP (ap)); + + priv = NM_AP_GET_PRIVATE (ap); + + if (priv->freq != freq) { + priv->freq = freq; + g_object_notify (G_OBJECT (ap), NM_AP_FREQUENCY); + } +} + +guint32 +nm_ap_get_max_bitrate (NMAccessPoint *ap) +{ + g_return_val_if_fail (NM_IS_AP (ap), 0); + g_return_val_if_fail (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (ap)), 0); + + return NM_AP_GET_PRIVATE (ap)->max_bitrate; +} + +void +nm_ap_set_max_bitrate (NMAccessPoint *ap, guint32 bitrate) +{ + NMAccessPointPrivate *priv; + + g_return_if_fail (NM_IS_AP (ap)); + + priv = NM_AP_GET_PRIVATE (ap); + + if (priv->max_bitrate != bitrate) { + priv->max_bitrate = bitrate; + g_object_notify (G_OBJECT (ap), NM_AP_MAX_BITRATE); + } +} + +gboolean +nm_ap_get_fake (const NMAccessPoint *ap) +{ + g_return_val_if_fail (NM_IS_AP (ap), FALSE); + + return NM_AP_GET_PRIVATE (ap)->fake; +} + +void +nm_ap_set_fake (NMAccessPoint *ap, gboolean fake) +{ + g_return_if_fail (NM_IS_AP (ap)); + + NM_AP_GET_PRIVATE (ap)->fake = fake; +} + +static void +nm_ap_set_last_seen (NMAccessPoint *ap, gint32 last_seen) +{ + NMAccessPointPrivate *priv; + + g_return_if_fail (NM_IS_AP (ap)); + + priv = NM_AP_GET_PRIVATE (ap); + + if (priv->last_seen != last_seen) { + priv->last_seen = last_seen; + g_object_notify (G_OBJECT (ap), NM_AP_LAST_SEEN); + } +} + +/*****************************************************************/ + +static NM80211ApSecurityFlags +security_from_vardict (GVariant *security) +{ + NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE; + const char **array, *tmp; + + g_return_val_if_fail (g_variant_is_of_type (security, G_VARIANT_TYPE_VARDICT), NM_802_11_AP_SEC_NONE); + + if (g_variant_lookup (security, "KeyMgmt", "^a&s", &array)) { + if (_nm_utils_string_in_list ("wpa-psk", array)) + flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK; + if (_nm_utils_string_in_list ("wpa-eap", array)) + flags |= NM_802_11_AP_SEC_KEY_MGMT_802_1X; + g_free (array); + } + + if (g_variant_lookup (security, "Pairwise", "^a&s", &array)) { + if (_nm_utils_string_in_list ("tkip", array)) + flags |= NM_802_11_AP_SEC_PAIR_TKIP; + if (_nm_utils_string_in_list ("ccmp", array)) + flags |= NM_802_11_AP_SEC_PAIR_CCMP; + g_free (array); + } + + if (g_variant_lookup (security, "Group", "&s", &tmp)) { + if (strcmp (tmp, "wep40") == 0) + flags |= NM_802_11_AP_SEC_GROUP_WEP40; + if (strcmp (tmp, "wep104") == 0) + flags |= NM_802_11_AP_SEC_GROUP_WEP104; + if (strcmp (tmp, "tkip") == 0) + flags |= NM_802_11_AP_SEC_GROUP_TKIP; + if (strcmp (tmp, "ccmp") == 0) + flags |= NM_802_11_AP_SEC_GROUP_CCMP; + } + + return flags; +} + +void +nm_ap_update_from_properties (NMAccessPoint *ap, + const char *supplicant_path, + GVariant *properties) +{ + NMAccessPointPrivate *priv; + char *addr; const guint8 *bytes; - NMAccessPoint *ap; GVariant *v; gsize len; gboolean b = FALSE; @@ -397,14 +393,14 @@ nm_ap_new_from_properties (const char *supplicant_path, GVariant *properties) gint16 i16; guint16 u16; - g_return_val_if_fail (properties != NULL, NULL); - - ap = nm_ap_new (); + g_return_if_fail (ap != NULL); + g_return_if_fail (properties != NULL); + priv = NM_AP_GET_PRIVATE (ap); g_object_freeze_notify (G_OBJECT (ap)); if (g_variant_lookup (properties, "Privacy", "b", &b) && b) - nm_ap_set_flags (ap, nm_ap_get_flags (ap) | NM_802_11_AP_FLAGS_PRIVACY); + nm_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_PRIVACY); if (g_variant_lookup (properties, "Mode", "&s", &s)) { if (!g_strcmp0 (s, "infrastructure")) @@ -437,11 +433,9 @@ nm_ap_new_from_properties (const char *supplicant_path, GVariant *properties) if (v) { bytes = g_variant_get_fixed_array (v, &len, 1); if (len == ETH_ALEN) { - char *a; - - a = nm_utils_hwaddr_ntoa (bytes, len); - nm_ap_set_address (ap, a); - g_free (a); + addr = nm_utils_hwaddr_ntoa (bytes, len); + nm_ap_set_address (ap, addr); + g_free (addr); } g_variant_unref (v); } @@ -464,17 +458,38 @@ nm_ap_new_from_properties (const char *supplicant_path, GVariant *properties) v = g_variant_lookup_value (properties, "WPA", G_VARIANT_TYPE_VARDICT); if (v) { - nm_ap_set_wpa_flags (ap, nm_ap_get_wpa_flags (ap) | security_from_vardict (v)); + nm_ap_set_wpa_flags (ap, priv->wpa_flags | security_from_vardict (v)); g_variant_unref (v); } v = g_variant_lookup_value (properties, "RSN", G_VARIANT_TYPE_VARDICT); if (v) { - nm_ap_set_rsn_flags (ap, nm_ap_get_rsn_flags (ap) | security_from_vardict (v)); + nm_ap_set_rsn_flags (ap, priv->rsn_flags | security_from_vardict (v)); g_variant_unref (v); } - nm_ap_set_supplicant_path (ap, supplicant_path); + if (!priv->supplicant_path) + priv->supplicant_path = g_strdup (supplicant_path); + + nm_ap_set_last_seen (ap, nm_utils_get_monotonic_timestamp_s ()); + priv->fake = FALSE; + + g_object_thaw_notify (G_OBJECT (ap)); +} + +NMAccessPoint * +nm_ap_new_from_properties (const char *supplicant_path, GVariant *properties) +{ + const char bad_bssid1[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + const char bad_bssid2[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + NMAccessPoint *ap; + const char *addr; + + g_return_val_if_fail (supplicant_path != NULL, NULL); + g_return_val_if_fail (properties != NULL, NULL); + + ap = (NMAccessPoint *) g_object_new (NM_TYPE_AP, NULL); + nm_ap_update_from_properties (ap, supplicant_path, properties); /* ignore APs with invalid or missing BSSIDs */ addr = nm_ap_get_address (ap); @@ -485,13 +500,6 @@ nm_ap_new_from_properties (const char *supplicant_path, GVariant *properties) return NULL; } - nm_ap_set_last_seen (ap, nm_utils_get_monotonic_timestamp_s ()); - - if (!nm_ap_get_ssid (ap)) - nm_ap_set_broadcast (ap, FALSE); - - g_object_thaw_notify (G_OBJECT (ap)); - return ap; } @@ -517,6 +525,7 @@ has_proto (NMSettingWirelessSecurity *sec, const char *proto) static void add_pair_ciphers (NMAccessPoint *ap, NMSettingWirelessSecurity *sec) { + NMAccessPointPrivate *priv = NM_AP_GET_PRIVATE (ap); guint32 num = nm_setting_wireless_security_get_num_pairwise (sec); NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE; guint32 i; @@ -536,14 +545,15 @@ add_pair_ciphers (NMAccessPoint *ap, NMSettingWirelessSecurity *sec) } if (has_proto (sec, PROTO_WPA)) - nm_ap_set_wpa_flags (ap, nm_ap_get_wpa_flags (ap) | flags); + nm_ap_set_wpa_flags (ap, priv->wpa_flags | flags); if (has_proto (sec, PROTO_RSN)) - nm_ap_set_rsn_flags (ap, nm_ap_get_rsn_flags (ap) | flags); + nm_ap_set_rsn_flags (ap, priv->rsn_flags | flags); } static void add_group_ciphers (NMAccessPoint *ap, NMSettingWirelessSecurity *sec) { + NMAccessPointPrivate *priv = NM_AP_GET_PRIVATE (ap); guint32 num = nm_setting_wireless_security_get_num_groups (sec); NM80211ApSecurityFlags flags = NM_802_11_AP_SEC_NONE; guint32 i; @@ -567,15 +577,16 @@ add_group_ciphers (NMAccessPoint *ap, NMSettingWirelessSecurity *sec) } if (has_proto (sec, PROTO_WPA)) - nm_ap_set_wpa_flags (ap, nm_ap_get_wpa_flags (ap) | flags); + nm_ap_set_wpa_flags (ap, priv->wpa_flags | flags); if (has_proto (sec, PROTO_RSN)) - nm_ap_set_rsn_flags (ap, nm_ap_get_rsn_flags (ap) | flags); + nm_ap_set_rsn_flags (ap, priv->rsn_flags | flags); } NMAccessPoint * nm_ap_new_fake_from_connection (NMConnection *connection) { NMAccessPoint *ap; + NMAccessPointPrivate *priv; NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_wireless_sec; GBytes *ssid; @@ -587,508 +598,172 @@ nm_ap_new_fake_from_connection (NMConnection *connection) g_return_val_if_fail (connection != NULL, NULL); s_wireless = nm_connection_get_setting_wireless (connection); - g_return_val_if_fail (s_wireless != NULL, NULL); - - ssid = nm_setting_wireless_get_ssid (s_wireless); - g_return_val_if_fail (ssid != NULL, NULL); - g_return_val_if_fail (g_bytes_get_size (ssid) > 0, NULL); - - ap = nm_ap_new (); - nm_ap_set_fake (ap, TRUE); - nm_ap_set_ssid (ap, g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid)); - - // FIXME: bssid too? - - mode = nm_setting_wireless_get_mode (s_wireless); - if (mode) { - if (!strcmp (mode, "infrastructure")) - nm_ap_set_mode (ap, NM_802_11_MODE_INFRA); - else if (!strcmp (mode, "adhoc")) - nm_ap_set_mode (ap, NM_802_11_MODE_ADHOC); - else if (!strcmp (mode, "ap")) { - nm_ap_set_mode (ap, NM_802_11_MODE_INFRA); - NM_AP_GET_PRIVATE (ap)->hotspot = TRUE; - } else - goto error; - } else { - nm_ap_set_mode (ap, NM_802_11_MODE_INFRA); - } - - band = nm_setting_wireless_get_band (s_wireless); - channel = nm_setting_wireless_get_channel (s_wireless); - - if (band && channel) { - guint32 freq = nm_utils_wifi_channel_to_freq (channel, band); - - if (freq == 0) - goto error; - - nm_ap_set_freq (ap, freq); - } - - s_wireless_sec = nm_connection_get_setting_wireless_security (connection); - /* Assume presence of a security setting means the AP is encrypted */ - if (!s_wireless_sec) - goto done; - - key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec); - - /* Everything below here uses encryption */ - nm_ap_set_flags (ap, nm_ap_get_flags (ap) | NM_802_11_AP_FLAGS_PRIVACY); - - /* Static & Dynamic WEP */ - if (!strcmp (key_mgmt, "none") || !strcmp (key_mgmt, "ieee8021x")) - goto done; - - psk = !strcmp (key_mgmt, "wpa-psk"); - eap = !strcmp (key_mgmt, "wpa-eap"); - if (psk || eap) { - if (has_proto (s_wireless_sec, PROTO_WPA)) { - flags = nm_ap_get_wpa_flags (ap); - flags |= eap ? NM_802_11_AP_SEC_KEY_MGMT_802_1X : NM_802_11_AP_SEC_KEY_MGMT_PSK; - nm_ap_set_wpa_flags (ap, flags); - } - if (has_proto (s_wireless_sec, PROTO_RSN)) { - flags = nm_ap_get_rsn_flags (ap); - flags |= eap ? NM_802_11_AP_SEC_KEY_MGMT_802_1X : NM_802_11_AP_SEC_KEY_MGMT_PSK; - nm_ap_set_rsn_flags (ap, flags); - } - - add_pair_ciphers (ap, s_wireless_sec); - add_group_ciphers (ap, s_wireless_sec); - } else if (!strcmp (key_mgmt, "wpa-none")) { - guint32 i; - - /* Ad-Hoc has special requirements: proto=WPA, pairwise=(none), and - * group=TKIP/CCMP (but not both). - */ - - flags = nm_ap_get_wpa_flags (ap); - flags |= NM_802_11_AP_SEC_KEY_MGMT_PSK; - - /* Clear ciphers; pairwise must be unset anyway, and group gets set below */ - flags &= ~( NM_802_11_AP_SEC_PAIR_WEP40 - | NM_802_11_AP_SEC_PAIR_WEP104 - | NM_802_11_AP_SEC_PAIR_TKIP - | NM_802_11_AP_SEC_PAIR_CCMP - | NM_802_11_AP_SEC_GROUP_WEP40 - | NM_802_11_AP_SEC_GROUP_WEP104 - | NM_802_11_AP_SEC_GROUP_TKIP - | NM_802_11_AP_SEC_GROUP_CCMP); - - for (i = 0; i < nm_setting_wireless_security_get_num_groups (s_wireless_sec); i++) { - if (!strcmp (nm_setting_wireless_security_get_group (s_wireless_sec, i), "ccmp")) { - flags |= NM_802_11_AP_SEC_GROUP_CCMP; - break; - } - } - - /* Default to TKIP since not all WPA-capable cards can do CCMP */ - if (!(flags & NM_802_11_AP_SEC_GROUP_CCMP)) - flags |= NM_802_11_AP_SEC_GROUP_TKIP; - - nm_ap_set_wpa_flags (ap, flags); - - /* Don't use Ad-Hoc RSN yet */ - nm_ap_set_rsn_flags (ap, NM_802_11_AP_SEC_NONE); - } - -done: - return ap; - -error: - g_object_unref (ap); - return NULL; -} - -void -nm_ap_dump (NMAccessPoint *ap, const char *prefix) -{ - NMAccessPointPrivate *priv; - - g_return_if_fail (NM_IS_AP (ap)); - - priv = NM_AP_GET_PRIVATE (ap); - - nm_log_dbg (LOGD_WIFI_SCAN, "%s'%s' (%p)", - prefix, - priv->ssid ? nm_utils_escape_ssid (priv->ssid->data, priv->ssid->len) : "(none)", - ap); - nm_log_dbg (LOGD_WIFI_SCAN, " BSSID %s", str_if_set (priv->address, "(none)")); - nm_log_dbg (LOGD_WIFI_SCAN, " mode %d", priv->mode); - nm_log_dbg (LOGD_WIFI_SCAN, " flags 0x%X", priv->flags); - nm_log_dbg (LOGD_WIFI_SCAN, " wpa flags 0x%X", priv->wpa_flags); - nm_log_dbg (LOGD_WIFI_SCAN, " rsn flags 0x%X", priv->rsn_flags); - nm_log_dbg (LOGD_WIFI_SCAN, " quality %d", priv->strength); - nm_log_dbg (LOGD_WIFI_SCAN, " frequency %d", priv->freq); - nm_log_dbg (LOGD_WIFI_SCAN, " max rate %d", priv->max_bitrate); - nm_log_dbg (LOGD_WIFI_SCAN, " last-seen %d", (int) priv->last_seen); -} - -const char * -nm_ap_get_dbus_path (NMAccessPoint *ap) -{ - g_return_val_if_fail (NM_IS_AP (ap), NULL); - - return NM_AP_GET_PRIVATE (ap)->dbus_path; -} - -const char * -nm_ap_get_supplicant_path (NMAccessPoint *ap) -{ - g_return_val_if_fail (NM_IS_AP (ap), NULL); - - return NM_AP_GET_PRIVATE (ap)->supplicant_path; -} - -void -nm_ap_set_supplicant_path (NMAccessPoint *ap, const char *path) -{ - g_return_if_fail (NM_IS_AP (ap)); - g_return_if_fail (path != NULL); - - g_free (NM_AP_GET_PRIVATE (ap)->supplicant_path); - NM_AP_GET_PRIVATE (ap)->supplicant_path = g_strdup (path); -} - -/* - * Get/set functions for ssid - * - */ -const GByteArray * nm_ap_get_ssid (const NMAccessPoint *ap) -{ - g_return_val_if_fail (NM_IS_AP (ap), NULL); - - return NM_AP_GET_PRIVATE (ap)->ssid; -} - -void -nm_ap_set_ssid (NMAccessPoint *ap, const guint8 *ssid, gsize len) -{ - NMAccessPointPrivate *priv; - - g_return_if_fail (NM_IS_AP (ap)); - g_return_if_fail (ssid == NULL || len > 0); - - priv = NM_AP_GET_PRIVATE (ap); - - /* same SSID */ - if ((ssid && priv->ssid) && (len == priv->ssid->len)) { - if (!memcmp (ssid, priv->ssid->data, len)) - return; - } - - if (priv->ssid) { - g_byte_array_free (priv->ssid, TRUE); - priv->ssid = NULL; - } - - if (ssid) { - priv->ssid = g_byte_array_new (); - g_byte_array_append (priv->ssid, ssid, len); - } - - g_object_notify (G_OBJECT (ap), NM_AP_SSID); -} - - -NM80211ApFlags -nm_ap_get_flags (NMAccessPoint *ap) -{ - g_return_val_if_fail (NM_IS_AP (ap), NM_802_11_AP_FLAGS_NONE); - - return NM_AP_GET_PRIVATE (ap)->flags; -} - - -void -nm_ap_set_flags (NMAccessPoint *ap, NM80211ApFlags flags) -{ - NMAccessPointPrivate *priv; - - g_return_if_fail (NM_IS_AP (ap)); - - priv = NM_AP_GET_PRIVATE (ap); - - if (priv->flags != flags) { - priv->flags = flags; - g_object_notify (G_OBJECT (ap), NM_AP_FLAGS); - } -} - -NM80211ApSecurityFlags -nm_ap_get_wpa_flags (NMAccessPoint *ap) -{ - g_return_val_if_fail (NM_IS_AP (ap), NM_802_11_AP_SEC_NONE); - - return NM_AP_GET_PRIVATE (ap)->wpa_flags; -} - - -void -nm_ap_set_wpa_flags (NMAccessPoint *ap, NM80211ApSecurityFlags flags) -{ - NMAccessPointPrivate *priv; - - g_return_if_fail (NM_IS_AP (ap)); - - priv = NM_AP_GET_PRIVATE (ap); - if (priv->wpa_flags != flags) { - priv->wpa_flags = flags; - g_object_notify (G_OBJECT (ap), NM_AP_WPA_FLAGS); - } -} - -NM80211ApSecurityFlags -nm_ap_get_rsn_flags (NMAccessPoint *ap) -{ - g_return_val_if_fail (NM_IS_AP (ap), NM_802_11_AP_SEC_NONE); - - return NM_AP_GET_PRIVATE (ap)->rsn_flags; -} - - -void -nm_ap_set_rsn_flags (NMAccessPoint *ap, NM80211ApSecurityFlags flags) -{ - NMAccessPointPrivate *priv; - - g_return_if_fail (NM_IS_AP (ap)); - - priv = NM_AP_GET_PRIVATE (ap); - if (priv->rsn_flags != flags) { - priv->rsn_flags = flags; - g_object_notify (G_OBJECT (ap), NM_AP_RSN_FLAGS); - } -} - -/* - * Get/set functions for address - * - */ -const char * -nm_ap_get_address (const NMAccessPoint *ap) -{ - g_return_val_if_fail (NM_IS_AP (ap), NULL); - - return NM_AP_GET_PRIVATE (ap)->address; -} - -void -nm_ap_set_address (NMAccessPoint *ap, const char *addr) -{ - NMAccessPointPrivate *priv; - - g_return_if_fail (NM_IS_AP (ap)); - g_return_if_fail (addr != NULL); - g_return_if_fail (nm_utils_hwaddr_valid (addr, ETH_ALEN)); - - priv = NM_AP_GET_PRIVATE (ap); - - if (!priv->address || !nm_utils_hwaddr_matches (addr, -1, priv->address, -1)) { - g_free (priv->address); - priv->address = g_strdup (addr); - g_object_notify (G_OBJECT (ap), NM_AP_HW_ADDRESS); - } -} - - -/* - * Get/set functions for mode (ie Ad-Hoc, Infrastructure, etc) - * - */ -NM80211Mode nm_ap_get_mode (NMAccessPoint *ap) -{ - NM80211Mode mode; - - g_return_val_if_fail (NM_IS_AP (ap), -1); - - g_object_get (ap, NM_AP_MODE, &mode, NULL); - - return mode; -} - -void nm_ap_set_mode (NMAccessPoint *ap, const NM80211Mode mode) -{ - NMAccessPointPrivate *priv; - - g_return_if_fail (NM_IS_AP (ap)); - g_return_if_fail ( mode == NM_802_11_MODE_ADHOC - || mode == NM_802_11_MODE_INFRA); - - priv = NM_AP_GET_PRIVATE (ap); - - if (priv->mode != mode) { - priv->mode = mode; - g_object_notify (G_OBJECT (ap), NM_AP_MODE); - } -} - -gboolean -nm_ap_is_hotspot (NMAccessPoint *ap) -{ - g_return_val_if_fail (NM_IS_AP (ap), FALSE); - - return NM_AP_GET_PRIVATE (ap)->hotspot; -} - -/* - * Get/set functions for strength - * - */ -gint8 nm_ap_get_strength (NMAccessPoint *ap) -{ - gint8 strength; - - g_return_val_if_fail (NM_IS_AP (ap), 0); - - g_object_get (ap, NM_AP_STRENGTH, &strength, NULL); - - return strength; -} - -void nm_ap_set_strength (NMAccessPoint *ap, const gint8 strength) -{ - NMAccessPointPrivate *priv; - - g_return_if_fail (NM_IS_AP (ap)); - - priv = NM_AP_GET_PRIVATE (ap); - - if (priv->strength != strength) { - priv->strength = strength; - g_object_notify (G_OBJECT (ap), NM_AP_STRENGTH); - } -} - - -/* - * Get/set functions for frequency - * - */ -guint32 -nm_ap_get_freq (NMAccessPoint *ap) -{ - guint32 freq; - - g_return_val_if_fail (NM_IS_AP (ap), 0); - - g_object_get (ap, NM_AP_FREQUENCY, &freq, NULL); - - return freq; -} - -void -nm_ap_set_freq (NMAccessPoint *ap, - const guint32 freq) -{ - NMAccessPointPrivate *priv; + g_return_val_if_fail (s_wireless != NULL, NULL); - g_return_if_fail (NM_IS_AP (ap)); + ssid = nm_setting_wireless_get_ssid (s_wireless); + g_return_val_if_fail (ssid != NULL, NULL); + g_return_val_if_fail (g_bytes_get_size (ssid) > 0, NULL); + ap = (NMAccessPoint *) g_object_new (NM_TYPE_AP, NULL); priv = NM_AP_GET_PRIVATE (ap); + priv->fake = TRUE; + nm_ap_set_ssid (ap, g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid)); - if (priv->freq != freq) { - priv->freq = freq; - g_object_notify (G_OBJECT (ap), NM_AP_FREQUENCY); + // FIXME: bssid too? + + mode = nm_setting_wireless_get_mode (s_wireless); + if (mode) { + if (!strcmp (mode, "infrastructure")) + nm_ap_set_mode (ap, NM_802_11_MODE_INFRA); + else if (!strcmp (mode, "adhoc")) + nm_ap_set_mode (ap, NM_802_11_MODE_ADHOC); + else if (!strcmp (mode, "ap")) { + nm_ap_set_mode (ap, NM_802_11_MODE_INFRA); + NM_AP_GET_PRIVATE (ap)->hotspot = TRUE; + } else + goto error; + } else { + nm_ap_set_mode (ap, NM_802_11_MODE_INFRA); } -} + band = nm_setting_wireless_get_band (s_wireless); + channel = nm_setting_wireless_get_channel (s_wireless); -/* - * Get/set functions for max bitrate (in kbit/s) - * - */ -guint32 nm_ap_get_max_bitrate (NMAccessPoint *ap) -{ - guint32 rate; + if (band && channel) { + guint32 freq = nm_utils_wifi_channel_to_freq (channel, band); - g_return_val_if_fail (NM_IS_AP (ap), 0); + if (freq == 0) + goto error; - g_object_get (ap, NM_AP_MAX_BITRATE, &rate, NULL); + nm_ap_set_freq (ap, freq); + } - return rate; -} + s_wireless_sec = nm_connection_get_setting_wireless_security (connection); + /* Assume presence of a security setting means the AP is encrypted */ + if (!s_wireless_sec) + goto done; -void -nm_ap_set_max_bitrate (NMAccessPoint *ap, guint32 bitrate) -{ - NMAccessPointPrivate *priv; + key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wireless_sec); - g_return_if_fail (NM_IS_AP (ap)); + /* Everything below here uses encryption */ + nm_ap_set_flags (ap, priv->flags | NM_802_11_AP_FLAGS_PRIVACY); - priv = NM_AP_GET_PRIVATE (ap); + /* Static & Dynamic WEP */ + if (!strcmp (key_mgmt, "none") || !strcmp (key_mgmt, "ieee8021x")) + goto done; - if (priv->max_bitrate != bitrate) { - priv->max_bitrate = bitrate; - g_object_notify (G_OBJECT (ap), NM_AP_MAX_BITRATE); - } -} + psk = !strcmp (key_mgmt, "wpa-psk"); + eap = !strcmp (key_mgmt, "wpa-eap"); + if (psk || eap) { + if (has_proto (s_wireless_sec, PROTO_WPA)) { + flags = priv->wpa_flags | (eap ? NM_802_11_AP_SEC_KEY_MGMT_802_1X : NM_802_11_AP_SEC_KEY_MGMT_PSK); + nm_ap_set_wpa_flags (ap, flags); + } + if (has_proto (s_wireless_sec, PROTO_RSN)) { + flags = priv->rsn_flags | (eap ? NM_802_11_AP_SEC_KEY_MGMT_802_1X : NM_802_11_AP_SEC_KEY_MGMT_PSK); + nm_ap_set_rsn_flags (ap, flags); + } -/* - * Get/Set functions to indicate that an access point is 'fake', ie whether - * or not it was created from scan results - */ -gboolean nm_ap_get_fake (const NMAccessPoint *ap) -{ - g_return_val_if_fail (NM_IS_AP (ap), FALSE); + add_pair_ciphers (ap, s_wireless_sec); + add_group_ciphers (ap, s_wireless_sec); + } else if (!strcmp (key_mgmt, "wpa-none")) { + guint32 i; - return NM_AP_GET_PRIVATE (ap)->fake; -} + /* Ad-Hoc has special requirements: proto=WPA, pairwise=(none), and + * group=TKIP/CCMP (but not both). + */ -void nm_ap_set_fake (NMAccessPoint *ap, gboolean fake) -{ - g_return_if_fail (NM_IS_AP (ap)); + flags = priv->wpa_flags | NM_802_11_AP_SEC_KEY_MGMT_PSK; - NM_AP_GET_PRIVATE (ap)->fake = fake; -} + /* Clear ciphers; pairwise must be unset anyway, and group gets set below */ + flags &= ~( NM_802_11_AP_SEC_PAIR_WEP40 + | NM_802_11_AP_SEC_PAIR_WEP104 + | NM_802_11_AP_SEC_PAIR_TKIP + | NM_802_11_AP_SEC_PAIR_CCMP + | NM_802_11_AP_SEC_GROUP_WEP40 + | NM_802_11_AP_SEC_GROUP_WEP104 + | NM_802_11_AP_SEC_GROUP_TKIP + | NM_802_11_AP_SEC_GROUP_CCMP); + for (i = 0; i < nm_setting_wireless_security_get_num_groups (s_wireless_sec); i++) { + if (!strcmp (nm_setting_wireless_security_get_group (s_wireless_sec, i), "ccmp")) { + flags |= NM_802_11_AP_SEC_GROUP_CCMP; + break; + } + } -/* - * Get/Set functions to indicate whether an AP broadcasts its SSID. - */ -gboolean nm_ap_get_broadcast (NMAccessPoint *ap) -{ - g_return_val_if_fail (NM_IS_AP (ap), TRUE); + /* Default to TKIP since not all WPA-capable cards can do CCMP */ + if (!(flags & NM_802_11_AP_SEC_GROUP_CCMP)) + flags |= NM_802_11_AP_SEC_GROUP_TKIP; - return NM_AP_GET_PRIVATE (ap)->broadcast; -} + nm_ap_set_wpa_flags (ap, flags); + /* Don't use Ad-Hoc RSN yet */ + nm_ap_set_rsn_flags (ap, NM_802_11_AP_SEC_NONE); + } -void nm_ap_set_broadcast (NMAccessPoint *ap, gboolean broadcast) -{ - g_return_if_fail (NM_IS_AP (ap)); +done: + return ap; - NM_AP_GET_PRIVATE (ap)->broadcast = broadcast; +error: + g_object_unref (ap); + return NULL; } - -/* - * Get/Set functions for how long ago the AP was last seen in a scan. - * APs older than a certain date are dropped from the list. - * - */ -gint32 -nm_ap_get_last_seen (const NMAccessPoint *ap) +static char +mode_to_char (NMAccessPoint *self) { - g_return_val_if_fail (NM_IS_AP (ap), 0); + NMAccessPointPrivate *priv = NM_AP_GET_PRIVATE (self); - return NM_AP_GET_PRIVATE (ap)->last_seen; + if (priv->mode == NM_802_11_MODE_ADHOC) + return '*'; + if (priv->hotspot) + return '#'; + if (priv->fake) + return '-'; + return ' '; } void -nm_ap_set_last_seen (NMAccessPoint *ap, gint32 last_seen) +nm_ap_dump (NMAccessPoint *self, + const char *prefix, + const char *ifname) { NMAccessPointPrivate *priv; + const char *supplicant_id = "-"; + guint32 chan; - g_return_if_fail (NM_IS_AP (ap)); + g_return_if_fail (NM_IS_AP (self)); - priv = NM_AP_GET_PRIVATE (ap); + priv = NM_AP_GET_PRIVATE (self); + chan = nm_utils_wifi_freq_to_channel (priv->freq); + if (priv->supplicant_path) + supplicant_id = strrchr (priv->supplicant_path, '/'); - if (priv->last_seen != last_seen) { - priv->last_seen = last_seen; - g_object_notify (G_OBJECT (ap), NM_AP_LAST_SEEN); - } + nm_log_dbg (LOGD_WIFI_SCAN, "%s[%s%c] %-32s[%s%u %3u%% %c W:%04X R:%04X] [%3u] %s%s", + prefix, + str_if_set (priv->address, "(none)"), + mode_to_char (self), + priv->ssid ? nm_utils_escape_ssid (priv->ssid->data, priv->ssid->len) : "(none)", + chan > 99 ? "" : (chan > 9 ? " " : " "), + chan, + priv->strength, + priv->flags & NM_802_11_AP_FLAGS_PRIVACY ? 'P' : ' ', + priv->wpa_flags & 0xFFFF, + priv->rsn_flags & 0xFFFF, + priv->last_seen > 0 ? (nm_utils_get_monotonic_timestamp_s () - priv->last_seen) : -1, + ifname, + supplicant_id); +} + +static guint +freq_to_band (guint32 freq) +{ + if (freq >= 4915 && freq <= 5825) + return 5; + else if (freq >= 2412 && freq <= 2484) + return 2; + return 0; } gboolean @@ -1141,13 +816,12 @@ nm_ap_check_compatible (NMAccessPoint *self, band = nm_setting_wireless_get_band (s_wireless); if (band) { - if (!strcmp (band, "a")) { - if (priv->freq < 4915 || priv->freq > 5825) - return FALSE; - } else if (!strcmp (band, "bg")) { - if (priv->freq < 2412 || priv->freq > 2484) - return FALSE; - } + guint ap_band = freq_to_band (priv->freq); + + if (!strcmp (band, "a") && ap_band != 5) + return FALSE; + else if (!strcmp (band, "bg") && ap_band != 2) + return FALSE; } channel = nm_setting_wireless_get_channel (s_wireless); @@ -1162,10 +836,10 @@ nm_ap_check_compatible (NMAccessPoint *self, return nm_setting_wireless_ap_security_compatible (s_wireless, s_wireless_sec, - nm_ap_get_flags (self), - nm_ap_get_wpa_flags (self), - nm_ap_get_rsn_flags (self), - nm_ap_get_mode (self)); + priv->flags, + priv->wpa_flags, + priv->rsn_flags, + priv->mode); } gboolean @@ -1189,96 +863,188 @@ nm_ap_complete_connection (NMAccessPoint *self, error); } -static gboolean -capabilities_compatible (NM80211ApSecurityFlags a_flags, NM80211ApSecurityFlags b_flags) +/*****************************************************************/ + +static void +nm_ap_init (NMAccessPoint *ap) { - if (a_flags == b_flags) - return TRUE; + NMAccessPointPrivate *priv = NM_AP_GET_PRIVATE (ap); - /* Make sure there's a common key management method */ - if (!((a_flags & 0x300) & (b_flags & 0x300))) - return FALSE; + priv->mode = NM_802_11_MODE_INFRA; + priv->flags = NM_802_11_AP_FLAGS_NONE; + priv->wpa_flags = NM_802_11_AP_SEC_NONE; + priv->rsn_flags = NM_802_11_AP_SEC_NONE; + priv->last_seen = -1; +} - /* Ensure common pairwise ciphers */ - if (!((a_flags & 0xF) & (b_flags & 0xF))) - return FALSE; +static void +finalize (GObject *object) +{ + NMAccessPointPrivate *priv = NM_AP_GET_PRIVATE (object); - /* Ensure common group ciphers */ - if (!((a_flags & 0xF0) & (b_flags & 0xF0))) - return FALSE; + g_free (priv->supplicant_path); + if (priv->ssid) + g_byte_array_free (priv->ssid, TRUE); + g_free (priv->address); - return TRUE; + G_OBJECT_CLASS (nm_ap_parent_class)->finalize (object); } -NMAccessPoint * -nm_ap_match_in_list (NMAccessPoint *find_ap, - GSList *ap_list, - gboolean strict_match) +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMAccessPointPrivate *priv = NM_AP_GET_PRIVATE (object); + GVariant *ssid; + + switch (prop_id) { + case PROP_FLAGS: + g_value_set_uint (value, priv->flags); + break; + case PROP_WPA_FLAGS: + g_value_set_uint (value, priv->wpa_flags); + break; + case PROP_RSN_FLAGS: + g_value_set_uint (value, priv->rsn_flags); + break; + case PROP_SSID: + if (priv->ssid) { + ssid = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + priv->ssid->data, priv->ssid->len, 1); + } else + ssid = g_variant_new_array (G_VARIANT_TYPE_BYTE, NULL, 0); + g_value_take_variant (value, ssid); + break; + case PROP_FREQUENCY: + g_value_set_uint (value, priv->freq); + break; + case PROP_HW_ADDRESS: + g_value_set_string (value, priv->address); + break; + case PROP_MODE: + g_value_set_uint (value, priv->mode); + break; + case PROP_MAX_BITRATE: + g_value_set_uint (value, priv->max_bitrate); + break; + case PROP_STRENGTH: + g_value_set_uchar (value, priv->strength); + break; + case PROP_LAST_SEEN: + g_value_set_int (value, + priv->last_seen > 0 + ? (gint) nm_utils_monotonic_timestamp_as_boottime (priv->last_seen, NM_UTILS_NS_PER_SECOND) + : -1); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +nm_ap_class_init (NMAccessPointClass *ap_class) { - GSList *iter; + GObjectClass *object_class = G_OBJECT_CLASS (ap_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (ap_class); + const NM80211ApSecurityFlags all_sec_flags = NM_802_11_AP_SEC_NONE + | NM_802_11_AP_SEC_PAIR_WEP40 + | NM_802_11_AP_SEC_PAIR_WEP104 + | NM_802_11_AP_SEC_PAIR_TKIP + | NM_802_11_AP_SEC_PAIR_CCMP + | NM_802_11_AP_SEC_GROUP_WEP40 + | NM_802_11_AP_SEC_GROUP_WEP104 + | NM_802_11_AP_SEC_GROUP_TKIP + | NM_802_11_AP_SEC_GROUP_CCMP + | NM_802_11_AP_SEC_KEY_MGMT_PSK + | NM_802_11_AP_SEC_KEY_MGMT_802_1X; - g_return_val_if_fail (find_ap != NULL, NULL); + g_type_class_add_private (ap_class, sizeof (NMAccessPointPrivate)); - for (iter = ap_list; iter; iter = g_slist_next (iter)) { - NMAccessPoint * list_ap = NM_AP (iter->data); - const GByteArray * list_ssid = nm_ap_get_ssid (list_ap); - const char * list_addr = nm_ap_get_address (list_ap); + exported_object_class->export_path = NM_DBUS_PATH_ACCESS_POINT "/%u"; - const GByteArray * find_ssid = nm_ap_get_ssid (find_ap); - const char * find_addr = nm_ap_get_address (find_ap); + /* virtual methods */ + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->finalize = finalize; - /* SSID match; if both APs are hiding their SSIDs, - * let matching continue on BSSID and other properties - */ - if ( (!list_ssid && find_ssid) - || (list_ssid && !find_ssid)) - continue; - if ( list_ssid - && find_ssid - && !nm_utils_same_ssid (list_ssid->data, list_ssid->len, - find_ssid->data, find_ssid->len, - TRUE)) - continue; - - /* BSSID match */ - if ( (strict_match || nm_ethernet_address_is_valid (find_addr, -1)) - && nm_ethernet_address_is_valid (list_addr, -1) - && !nm_utils_hwaddr_matches (list_addr, -1, find_addr, -1)) - continue; - - /* mode match */ - if (nm_ap_get_mode (list_ap) != nm_ap_get_mode (find_ap)) - continue; - - /* Frequency match */ - if (nm_ap_get_freq (list_ap) != nm_ap_get_freq (find_ap)) - continue; - - /* AP flags */ - if (nm_ap_get_flags (list_ap) != nm_ap_get_flags (find_ap)) - continue; - - if (strict_match) { - if (nm_ap_get_wpa_flags (list_ap) != nm_ap_get_wpa_flags (find_ap)) - continue; - - if (nm_ap_get_rsn_flags (list_ap) != nm_ap_get_rsn_flags (find_ap)) - continue; - } else { - NM80211ApSecurityFlags list_wpa_flags = nm_ap_get_wpa_flags (list_ap); - NM80211ApSecurityFlags find_wpa_flags = nm_ap_get_wpa_flags (find_ap); - NM80211ApSecurityFlags list_rsn_flags = nm_ap_get_rsn_flags (list_ap); - NM80211ApSecurityFlags find_rsn_flags = nm_ap_get_rsn_flags (find_ap); - - /* Just ensure that there is overlap in the capabilities */ - if ( !capabilities_compatible (list_wpa_flags, find_wpa_flags) - && !capabilities_compatible (list_rsn_flags, find_rsn_flags)) - continue; - } + /* properties */ + g_object_class_install_property + (object_class, PROP_FLAGS, + g_param_spec_uint (NM_AP_FLAGS, "", "", + NM_802_11_AP_FLAGS_NONE, + NM_802_11_AP_FLAGS_PRIVACY, + NM_802_11_AP_FLAGS_NONE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - return list_ap; - } + g_object_class_install_property + (object_class, PROP_WPA_FLAGS, + g_param_spec_uint (NM_AP_WPA_FLAGS, "", "", + NM_802_11_AP_SEC_NONE, + all_sec_flags, + NM_802_11_AP_SEC_NONE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); - return NULL; + g_object_class_install_property + (object_class, PROP_RSN_FLAGS, + g_param_spec_uint (NM_AP_RSN_FLAGS, "", "", + NM_802_11_AP_SEC_NONE, + all_sec_flags, + NM_802_11_AP_SEC_NONE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_SSID, + g_param_spec_variant (NM_AP_SSID, "", "", + G_VARIANT_TYPE ("ay"), + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_FREQUENCY, + g_param_spec_uint (NM_AP_FREQUENCY, "", "", + 0, 10000, 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_HW_ADDRESS, + g_param_spec_string (NM_AP_HW_ADDRESS, "", "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_MODE, + g_param_spec_uint (NM_AP_MODE, "", "", + NM_802_11_MODE_ADHOC, NM_802_11_MODE_INFRA, NM_802_11_MODE_INFRA, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_MAX_BITRATE, + g_param_spec_uint (NM_AP_MAX_BITRATE, "", "", + 0, G_MAXUINT16, 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_STRENGTH, + g_param_spec_uchar (NM_AP_STRENGTH, "", "", + 0, G_MAXINT8, 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_LAST_SEEN, + g_param_spec_int (NM_AP_LAST_SEEN, "", "", + -1, G_MAXINT, -1, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (ap_class), + NMDBUS_TYPE_ACCESS_POINT_SKELETON, + NULL); } diff --git a/src/devices/wifi/nm-wifi-ap.h b/src/devices/wifi/nm-wifi-ap.h index 67d30769..84aff983 100644 --- a/src/devices/wifi/nm-wifi-ap.h +++ b/src/devices/wifi/nm-wifi-ap.h @@ -22,8 +22,7 @@ #ifndef __NETWORKMANAGER_ACCESS_POINT_H__ #define __NETWORKMANAGER_ACCESS_POINT_H__ -#include -#include +#include "nm-exported-object.h" #include "nm-dbus-interface.h" #include "nm-connection.h" @@ -46,77 +45,58 @@ #define NM_AP_LAST_SEEN "last-seen" typedef struct { - GObject parent; + NMExportedObject parent; } NMAccessPoint; typedef struct { - GObjectClass parent; + NMExportedObjectClass parent; } NMAccessPointClass; GType nm_ap_get_type (void); -NMAccessPoint * nm_ap_new_from_properties (const char *supplicant_path, - GVariant *properties); -NMAccessPoint * nm_ap_new_fake_from_connection (NMConnection *connection); -void nm_ap_export_to_dbus (NMAccessPoint *ap); - -const char *nm_ap_get_dbus_path (NMAccessPoint *ap); - -const char *nm_ap_get_supplicant_path (NMAccessPoint *ap); -void nm_ap_set_supplicant_path (NMAccessPoint *ap, - const char *path); - -const GByteArray *nm_ap_get_ssid (const NMAccessPoint * ap); -void nm_ap_set_ssid (NMAccessPoint * ap, const guint8 * ssid, gsize len); - -NM80211ApFlags nm_ap_get_flags (NMAccessPoint *ap); -void nm_ap_set_flags (NMAccessPoint *ap, NM80211ApFlags flags); - -NM80211ApSecurityFlags nm_ap_get_wpa_flags (NMAccessPoint *ap); -void nm_ap_set_wpa_flags (NMAccessPoint *ap, NM80211ApSecurityFlags flags); - -NM80211ApSecurityFlags nm_ap_get_rsn_flags (NMAccessPoint *ap); -void nm_ap_set_rsn_flags (NMAccessPoint *ap, NM80211ApSecurityFlags flags); - -const char *nm_ap_get_address (const NMAccessPoint *ap); -void nm_ap_set_address (NMAccessPoint *ap, const char *addr); - -NM80211Mode nm_ap_get_mode (NMAccessPoint *ap); -void nm_ap_set_mode (NMAccessPoint *ap, const NM80211Mode mode); - -gboolean nm_ap_is_hotspot (NMAccessPoint *ap); - -gint8 nm_ap_get_strength (NMAccessPoint *ap); -void nm_ap_set_strength (NMAccessPoint *ap, gint8 strength); - -guint32 nm_ap_get_freq (NMAccessPoint *ap); -void nm_ap_set_freq (NMAccessPoint *ap, guint32 freq); - -guint32 nm_ap_get_max_bitrate (NMAccessPoint *ap); -void nm_ap_set_max_bitrate (NMAccessPoint *ap, guint32 bitrate); - -gboolean nm_ap_get_fake (const NMAccessPoint *ap); -void nm_ap_set_fake (NMAccessPoint *ap, gboolean fake); - -gboolean nm_ap_get_broadcast (NMAccessPoint *ap); -void nm_ap_set_broadcast (NMAccessPoint *ap, gboolean broadcast); - -gint32 nm_ap_get_last_seen (const NMAccessPoint *ap); -void nm_ap_set_last_seen (NMAccessPoint *ap, gint32 last_seen); - -gboolean nm_ap_check_compatible (NMAccessPoint *self, - NMConnection *connection); - -gboolean nm_ap_complete_connection (NMAccessPoint *self, - NMConnection *connection, - gboolean lock_bssid, - GError **error); - -NMAccessPoint * nm_ap_match_in_list (NMAccessPoint *find_ap, - GSList *ap_list, - gboolean strict_match); - -void nm_ap_dump (NMAccessPoint *ap, const char *prefix); +NMAccessPoint * nm_ap_new_from_properties (const char *supplicant_path, + GVariant *properties); +NMAccessPoint * nm_ap_new_fake_from_connection (NMConnection *connection); + +void nm_ap_update_from_properties (NMAccessPoint *ap, + const char *supplicant_path, + GVariant *properties); + +gboolean nm_ap_check_compatible (NMAccessPoint *self, + NMConnection *connection); + +gboolean nm_ap_complete_connection (NMAccessPoint *self, + NMConnection *connection, + gboolean lock_bssid, + GError **error); + +const char * nm_ap_get_supplicant_path (NMAccessPoint *ap); +guint32 nm_ap_get_id (NMAccessPoint *ap); +const GByteArray *nm_ap_get_ssid (const NMAccessPoint *ap); +void nm_ap_set_ssid (NMAccessPoint *ap, + const guint8 *ssid, + gsize len); +const char * nm_ap_get_address (const NMAccessPoint *ap); +void nm_ap_set_address (NMAccessPoint *ap, + const char *addr); +NM80211Mode nm_ap_get_mode (NMAccessPoint *ap); +gboolean nm_ap_is_hotspot (NMAccessPoint *ap); +gint8 nm_ap_get_strength (NMAccessPoint *ap); +void nm_ap_set_strength (NMAccessPoint *ap, + gint8 strength); +guint32 nm_ap_get_freq (NMAccessPoint *ap); +void nm_ap_set_freq (NMAccessPoint *ap, + guint32 freq); +guint32 nm_ap_get_max_bitrate (NMAccessPoint *ap); +void nm_ap_set_max_bitrate (NMAccessPoint *ap, + guint32 bitrate); +gboolean nm_ap_get_fake (const NMAccessPoint *ap); +void nm_ap_set_fake (NMAccessPoint *ap, + gboolean fake); + +void nm_ap_dump (NMAccessPoint *self, + const char *prefix, + const char *ifname); #endif /* __NETWORKMANAGER_ACCESS_POINT_H__ */ diff --git a/src/devices/wifi/nm-wifi-enum-types.c b/src/devices/wifi/nm-wifi-enum-types.c deleted file mode 100644 index 7cce51cd..00000000 --- a/src/devices/wifi/nm-wifi-enum-types.c +++ /dev/null @@ -1,14 +0,0 @@ - - - -/* Generated by glib-mkenums. Do not edit */ - -#include "nm-wifi-enum-types.h" - -#include "nm-device-wifi.h" -#include "nm-wifi-ap.h" -#include "nm-device-olpc-mesh.h" - - - - diff --git a/src/devices/wifi/nm-wifi-enum-types.h b/src/devices/wifi/nm-wifi-enum-types.h deleted file mode 100644 index 7fc64cd1..00000000 --- a/src/devices/wifi/nm-wifi-enum-types.h +++ /dev/null @@ -1,17 +0,0 @@ - - - -/* Generated by glib-mkenums. Do not edit */ - -#ifndef __NM_WIFI_ENUM_TYPES_H__ -#define __NM_WIFI_ENUM_TYPES_H__ - -#include - -G_BEGIN_DECLS -G_END_DECLS - -#endif /* __NM_WIFI_ENUM_TYPES_H__ */ - - - diff --git a/src/devices/wifi/nm-wifi-factory.c b/src/devices/wifi/nm-wifi-factory.c index c4b4042e..7f56dc74 100644 --- a/src/devices/wifi/nm-wifi-factory.c +++ b/src/devices/wifi/nm-wifi-factory.c @@ -43,7 +43,7 @@ typedef struct { static GType nm_wifi_factory_get_type (void); -static void device_factory_interface_init (NMDeviceFactory *factory_iface); +static void device_factory_interface_init (NMDeviceFactoryInterface *factory_iface); G_DEFINE_TYPE_EXTENDED (NMWifiFactory, nm_wifi_factory, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_FACTORY, device_factory_interface_init)) @@ -59,13 +59,30 @@ nm_device_factory_create (GError **error) /**************************************************************************/ static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) { + NMDeviceWifiCapabilities capabilities; + + g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (plink != NULL, NULL); + g_return_val_if_fail (g_strcmp0 (iface, plink->name) == 0, NULL); + g_return_val_if_fail (NM_IN_SET (plink->type, NM_LINK_TYPE_WIFI, NM_LINK_TYPE_OLPC_MESH), NULL); + + if (!nm_platform_wifi_get_capabilities (NM_PLATFORM_GET, + plink->ifindex, + &capabilities)) { + nm_log_warn (LOGD_HW | LOGD_WIFI, "(%s) failed to initialize Wi-Fi driver for ifindex %d", iface, plink->ifindex); + return NULL; + } + if (plink->type == NM_LINK_TYPE_WIFI) - return nm_device_wifi_new (plink); - else if (plink->type == NM_LINK_TYPE_OLPC_MESH) - return nm_device_olpc_mesh_new (plink); - g_assert_not_reached (); + return nm_device_wifi_new (iface, capabilities); + else + return nm_device_olpc_mesh_new (iface); } NM_DEVICE_FACTORY_DECLARE_TYPES ( @@ -74,9 +91,9 @@ NM_DEVICE_FACTORY_DECLARE_TYPES ( ) static void -device_factory_interface_init (NMDeviceFactory *factory_iface) +device_factory_interface_init (NMDeviceFactoryInterface *factory_iface) { - factory_iface->new_link = new_link; + factory_iface->create_device = create_device; factory_iface->get_supported_types = get_supported_types; } diff --git a/src/devices/wifi/tests/Makefile.am b/src/devices/wifi/tests/Makefile.am index f76bdbf5..dee8e799 100644 --- a/src/devices/wifi/tests/Makefile.am +++ b/src/devices/wifi/tests/Makefile.am @@ -1,6 +1,7 @@ AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_builddir)/introspection \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -I${top_srcdir}/src/platform \ @@ -8,10 +9,9 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/devices/wifi \ -I$(top_builddir)/src \ -DG_LOG_DOMAIN=\""NetworkManager-wifi"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) + $(GLIB_CFLAGS) noinst_PROGRAMS = test-wifi-ap-utils diff --git a/src/devices/wifi/tests/Makefile.in b/src/devices/wifi/tests/Makefile.in index f2488c7d..90900f00 100644 --- a/src/devices/wifi/tests/Makefile.in +++ b/src/devices/wifi/tests/Makefile.in @@ -404,7 +404,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -416,8 +415,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -427,6 +424,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -481,16 +479,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -527,6 +522,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -555,7 +552,6 @@ 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@ @@ -570,6 +566,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -630,6 +628,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -637,6 +636,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -653,8 +653,9 @@ with_netconfig = @with_netconfig@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_builddir)/introspection \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -I${top_srcdir}/src/platform \ @@ -662,10 +663,9 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/devices/wifi \ -I$(top_builddir)/src \ -DG_LOG_DOMAIN=\""NetworkManager-wifi"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) + $(GLIB_CFLAGS) test_wifi_ap_utils_SOURCES = \ test-wifi-ap-utils.c \ diff --git a/src/devices/wifi/tests/test-wifi-ap-utils.c b/src/devices/wifi/tests/test-wifi-ap-utils.c index 26e130c4..b5642fe2 100644 --- a/src/devices/wifi/tests/test-wifi-ap-utils.c +++ b/src/devices/wifi/tests/test-wifi-ap-utils.c @@ -20,14 +20,15 @@ #include "config.h" -#include #include +#include "nm-default.h" #include "nm-wifi-ap-utils.h" -#include "nm-dbus-glib-types.h" #include "nm-core-internal.h" +#include "nm-test-utils.h" + #define DEBUG 1 /*******************************************/ @@ -1336,16 +1337,14 @@ test_strength_wext (void) /*******************************************/ +NMTST_DEFINE (); + int main (int argc, char **argv) { gsize i; -#if !GLIB_CHECK_VERSION (2, 35, 0) - g_type_init (); -#endif - - g_test_init (&argc, &argv, NULL); + nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); g_test_add_func ("/wifi/lock_bssid", test_lock_bssid); diff --git a/src/devices/wimax/Makefile.am b/src/devices/wimax/Makefile.am deleted file mode 100644 index 0ecd1158..00000000 --- a/src/devices/wimax/Makefile.am +++ /dev/null @@ -1,60 +0,0 @@ -AM_CPPFLAGS = \ - -I${top_srcdir}/src \ - -I${top_builddir}/src \ - -I${top_srcdir}/src/devices \ - -I${top_srcdir}/src/platform \ - -I${top_srcdir}/include \ - -I${top_builddir}/include \ - -I${top_builddir}/libnm-core \ - -I${top_srcdir}/libnm-core \ - -DG_LOG_DOMAIN=\""NetworkManager-wimax"\" \ - -DNETWORKMANAGER_COMPILATION \ - -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(DBUS_CFLAGS) \ - $(IWMX_SDK_CFLAGS) - -pkglib_LTLIBRARIES = libnm-device-plugin-wimax.la - -SYMBOL_VIS_FILE=$(srcdir)/exports.ver - -libnm_device_plugin_wimax_la_SOURCES = \ - nm-wimax-factory.c \ - nm-device-wimax.c \ - nm-device-wimax.h \ - nm-wimax-nsp.c \ - nm-wimax-nsp.h \ - nm-wimax-types.h \ - nm-wimax-util.c \ - nm-wimax-util.h \ - iwmxsdk.c \ - iwmxsdk.h - -libnm_device_plugin_wimax_la_LDFLAGS = \ - -module -avoid-version \ - -Wl,--version-script=$(SYMBOL_VIS_FILE) - -libnm_device_plugin_wimax_la_LIBADD = \ - $(DBUS_LIBS) \ - $(IWMX_SDK_LIBS) \ - $(GUDEV_LIBS) - -nm-wimax-nsp-glue.h: $(top_srcdir)/introspection/nm-wimax-nsp.xml - dbus-binding-tool --prefix=nm_wimax_nsp --mode=glib-server --output=$@ $< - -nm-device-wimax-glue.h: $(top_srcdir)/introspection/nm-device-wimax.xml - dbus-binding-tool --prefix=nm_device_wimax --mode=glib-server --output=$@ $< - -BUILT_SOURCES = \ - nm-wimax-nsp-glue.h \ - nm-device-wimax-glue.h - -CLEANFILES = $(BUILT_SOURCES) -EXTRA_DIST = $(SYMBOL_VIS_FILE) - -if ENABLE_TESTS - -check-local: - $(top_srcdir)/tools/check-exports.sh $(builddir)/.libs/libnm-device-plugin-wimax.so $(SYMBOL_VIS_FILE) - -endif - diff --git a/src/devices/wimax/Makefile.in b/src/devices/wimax/Makefile.in deleted file mode 100644 index b1b57a79..00000000 --- a/src/devices/wimax/Makefile.in +++ /dev/null @@ -1,866 +0,0 @@ -# Makefile.in generated by automake 1.15 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2014 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 = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = src/devices/wimax -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) -DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__installdirs = "$(DESTDIR)$(pkglibdir)" -LTLIBRARIES = $(pkglib_LTLIBRARIES) -am__DEPENDENCIES_1 = -libnm_device_plugin_wimax_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -am_libnm_device_plugin_wimax_la_OBJECTS = nm-wimax-factory.lo \ - nm-device-wimax.lo nm-wimax-nsp.lo nm-wimax-util.lo iwmxsdk.lo -libnm_device_plugin_wimax_la_OBJECTS = \ - $(am_libnm_device_plugin_wimax_la_OBJECTS) -AM_V_lt = $(am__v_lt_@AM_V@) -am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) -am__v_lt_0 = --silent -am__v_lt_1 = -libnm_device_plugin_wimax_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libnm_device_plugin_wimax_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(CFLAGS) -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = -CCLD = $(CC) -LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = -SOURCES = $(libnm_device_plugin_wimax_la_SOURCES) -DIST_SOURCES = $(libnm_device_plugin_wimax_la_SOURCES) -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -am__DIST_COMMON = $(srcdir)/Makefile.in \ - $(top_srcdir)/build-aux/depcomp -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -ALL_LINGUAS = @ALL_LINGUAS@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AM_TESTS_FD_REDIRECT = @AM_TESTS_FD_REDIRECT@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BLUEZ5_CFLAGS = @BLUEZ5_CFLAGS@ -BLUEZ5_LIBS = @BLUEZ5_LIBS@ -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@ -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_CHECK_PATH = @GTKDOC_CHECK_PATH@ -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@ -LOG_DRIVER = @LOG_DRIVER@ -LTLIBICONV = @LTLIBICONV@ -LTLIBINTL = @LTLIBINTL@ -LTLIBOBJS = @LTLIBOBJS@ -LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ -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_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ -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@ -PERL = @PERL@ -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_DIR = @UDEV_DIR@ -USE_NLS = @USE_NLS@ -UUID_CFLAGS = @UUID_CFLAGS@ -UUID_LIBS = @UUID_LIBS@ -VALGRIND_RULES = @VALGRIND_RULES@ -VAPIGEN = @VAPIGEN@ -VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@ -VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@ -VERSION = @VERSION@ -XGETTEXT = @XGETTEXT@ -XGETTEXT_015 = @XGETTEXT_015@ -XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -intltool__v_merge_options_ = @intltool__v_merge_options_@ -intltool__v_merge_options_0 = @intltool__v_merge_options_0@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -nmbinary = @nmbinary@ -nmconfdir = @nmconfdir@ -nmdatadir = @nmdatadir@ -nmrundir = @nmrundir@ -nmstatedir = @nmstatedir@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -subdirs = @subdirs@ -sysconfdir = @sysconfdir@ -systemdsystemunitdir = @systemdsystemunitdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -with_dhclient = @with_dhclient@ -with_dhcpcd = @with_dhcpcd@ -with_netconfig = @with_netconfig@ -with_resolvconf = @with_resolvconf@ -with_valgrind = @with_valgrind@ -AM_CPPFLAGS = \ - -I${top_srcdir}/src \ - -I${top_builddir}/src \ - -I${top_srcdir}/src/devices \ - -I${top_srcdir}/src/platform \ - -I${top_srcdir}/include \ - -I${top_builddir}/include \ - -I${top_builddir}/libnm-core \ - -I${top_srcdir}/libnm-core \ - -DG_LOG_DOMAIN=\""NetworkManager-wimax"\" \ - -DNETWORKMANAGER_COMPILATION \ - -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(DBUS_CFLAGS) \ - $(IWMX_SDK_CFLAGS) - -pkglib_LTLIBRARIES = libnm-device-plugin-wimax.la -SYMBOL_VIS_FILE = $(srcdir)/exports.ver -libnm_device_plugin_wimax_la_SOURCES = \ - nm-wimax-factory.c \ - nm-device-wimax.c \ - nm-device-wimax.h \ - nm-wimax-nsp.c \ - nm-wimax-nsp.h \ - nm-wimax-types.h \ - nm-wimax-util.c \ - nm-wimax-util.h \ - iwmxsdk.c \ - iwmxsdk.h - -libnm_device_plugin_wimax_la_LDFLAGS = \ - -module -avoid-version \ - -Wl,--version-script=$(SYMBOL_VIS_FILE) - -libnm_device_plugin_wimax_la_LIBADD = \ - $(DBUS_LIBS) \ - $(IWMX_SDK_LIBS) \ - $(GUDEV_LIBS) - -BUILT_SOURCES = \ - nm-wimax-nsp-glue.h \ - nm-device-wimax-glue.h - -CLEANFILES = $(BUILT_SOURCES) -EXTRA_DIST = $(SYMBOL_VIS_FILE) -all: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) all-am - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/devices/wimax/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/devices/wimax/Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) - @$(NORMAL_INSTALL) - @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ - } - -uninstall-pkglibLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ - done - -clean-pkglibLTLIBRARIES: - -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) - @list='$(pkglib_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } - -libnm-device-plugin-wimax.la: $(libnm_device_plugin_wimax_la_OBJECTS) $(libnm_device_plugin_wimax_la_DEPENDENCIES) $(EXTRA_libnm_device_plugin_wimax_la_DEPENDENCIES) - $(AM_V_CCLD)$(libnm_device_plugin_wimax_la_LINK) -rpath $(pkglibdir) $(libnm_device_plugin_wimax_la_OBJECTS) $(libnm_device_plugin_wimax_la_LIBADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iwmxsdk.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-device-wimax.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-wimax-factory.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-wimax-nsp.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-wimax-util.Plo@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< - -.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 -o $@ `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-am - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-am - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -@ENABLE_TESTS_FALSE@check-local: -check-am: all-am - $(MAKE) $(AM_MAKEFLAGS) check-local -check: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) check-am -all-am: Makefile $(LTLIBRARIES) -installdirs: - for dir in "$(DESTDIR)$(pkglibdir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." - -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -clean: clean-am - -clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \ - mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: install-pkglibLTLIBRARIES - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-pkglibLTLIBRARIES - -.MAKE: all check check-am install install-am install-strip - -.PHONY: CTAGS GTAGS TAGS all all-am check check-am check-local clean \ - clean-generic clean-libtool clean-pkglibLTLIBRARIES \ - cscopelist-am ctags ctags-am distclean distclean-compile \ - distclean-generic distclean-libtool distclean-tags distdir dvi \ - dvi-am html html-am info info-am install install-am \ - install-data install-data-am install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-man install-pdf \ - install-pdf-am install-pkglibLTLIBRARIES install-ps \ - install-ps-am install-strip installcheck installcheck-am \ - installdirs maintainer-clean maintainer-clean-generic \ - mostlyclean mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ - uninstall-am uninstall-pkglibLTLIBRARIES - -.PRECIOUS: Makefile - - -nm-wimax-nsp-glue.h: $(top_srcdir)/introspection/nm-wimax-nsp.xml - dbus-binding-tool --prefix=nm_wimax_nsp --mode=glib-server --output=$@ $< - -nm-device-wimax-glue.h: $(top_srcdir)/introspection/nm-device-wimax.xml - dbus-binding-tool --prefix=nm_device_wimax --mode=glib-server --output=$@ $< - -@ENABLE_TESTS_TRUE@check-local: -@ENABLE_TESTS_TRUE@ $(top_srcdir)/tools/check-exports.sh $(builddir)/.libs/libnm-device-plugin-wimax.so $(SYMBOL_VIS_FILE) - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/src/devices/wimax/exports.ver b/src/devices/wimax/exports.ver deleted file mode 100644 index 24cd848c..00000000 --- a/src/devices/wimax/exports.ver +++ /dev/null @@ -1,6 +0,0 @@ -{ -global: - nm_device_factory_create; -local: - *; -}; diff --git a/src/devices/wimax/iwmxsdk.c b/src/devices/wimax/iwmxsdk.c deleted file mode 100644 index 1c2c6821..00000000 --- a/src/devices/wimax/iwmxsdk.c +++ /dev/null @@ -1,1515 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* - * - * Copyright (C) 2011 Red Hat, Inc. All rights reserved. - * Copyright (C) 2007-2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include - -#include "nm-wimax-util.h" - -#include -#include - -#include "nm-logging.h" -#include "iwmxsdk.h" - -static WIMAX_API_DEVICE_ID g_api; -static GMutex add_remove_mutex; - -/* Misc utilities */ -#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) - -/* Misc values */ -enum { - /* - * WARNING!!!!! - * - * ONLY ONE DEVICE SUPPORTED - * - * - on removal, there is no way to know which device was - * removed (the removed device is removed from the list and - * the callback doesn't have any more information than the - * index in the list that getlistdevice would return -- racy - * as hell). - * - * - on insertion, there is not enough information provided. - */ - IWMX_SDK_DEV_MAX = 1, -}; - -/* Yes, this is dirty; see above on IWMX_SDK_DEV_MAX */ -static struct wmxsdk *g_iwmx_sdk_devs[IWMX_SDK_DEV_MAX]; - -static struct wmxsdk *deviceid_to_wmxsdk(WIMAX_API_DEVICE_ID *device_id) -{ - unsigned cnt; - for (cnt = 0; cnt < IWMX_SDK_DEV_MAX; cnt++) { - struct wmxsdk *wmxsdk = g_iwmx_sdk_devs[cnt]; - if (wmxsdk && - wmxsdk->device_id.deviceIndex == device_id->deviceIndex) - return wmxsdk; - } - return NULL; -} - -static int deviceid_to_index(WIMAX_API_DEVICE_ID *device_id) -{ - unsigned cnt; - - for (cnt = 0; cnt < IWMX_SDK_DEV_MAX; cnt++) { - struct wmxsdk *wmxsdk = g_iwmx_sdk_devs[cnt]; - if (wmxsdk && wmxsdk->device_id.deviceIndex == device_id->deviceIndex) - return cnt; - } - return -1; -} - -struct wmxsdk *iwmx_sdk_get_wmxsdk_for_iface(const char *iface) -{ - unsigned cnt; - - for (cnt = 0; cnt < IWMX_SDK_DEV_MAX; cnt++) { - struct wmxsdk *wmxsdk = g_iwmx_sdk_devs[cnt]; - if (wmxsdk && !strcmp(wmxsdk->ifname, iface)) - return wmxsdk; - } - return NULL; -} - -/* - * FIXME: pulled it it out of some hole - * - * the cinr to percentage computation comes from the L3/L4 doc - * - * But some other places (L4 code) have a more complex, seemingly - * logarithmical computation. - * - * Oh well... - * - */ -static int cinr_to_percentage(int cinr) -{ - int strength; - if (cinr <= -5) - strength = 0; - else if (cinr >= 25) - strength = 100; - else /* Calc percentage on the value from -5 to 25 */ - strength = ((100UL * (cinr - -5)) / (25 - -5)); - return strength; -} - -/**************************************************************/ - -typedef struct { - WimaxNewWmxsdkFunc callback; - void *user_data; -} NewSdkCallback; - -static GMutex new_callbacks_mutex; -static GSList *new_callbacks = NULL; - -void iwmx_sdk_new_callback_register(WimaxNewWmxsdkFunc callback, void *user_data) -{ - NewSdkCallback *cb; - - cb = g_malloc0 (sizeof (NewSdkCallback)); - g_assert (cb); - cb->callback = callback; - cb->user_data = user_data; - - g_mutex_lock (&new_callbacks_mutex); - new_callbacks = g_slist_append (new_callbacks, cb); - g_mutex_unlock (&new_callbacks_mutex); -} - -void iwmx_sdk_new_callback_unregister(WimaxNewWmxsdkFunc callback, void *user_data) -{ - GSList *iter; - NewSdkCallback *found = NULL; - - g_mutex_lock (&new_callbacks_mutex); - for (iter = new_callbacks; iter; iter = g_slist_next (iter)) { - NewSdkCallback *cb = iter->data; - - if (cb->callback == callback && cb->user_data == user_data) { - found = cb; - break; - } - } - - if (found) { - new_callbacks = g_slist_remove (new_callbacks, found); - g_free (found); - } - g_mutex_unlock (&new_callbacks_mutex); -} - -static void iwmx_sdk_call_new_callbacks(struct wmxsdk *wmxsdk) -{ - GSList *iter; - - g_mutex_lock (&new_callbacks_mutex); - for (iter = new_callbacks; iter; iter = g_slist_next (iter)) { - NewSdkCallback *cb = iter->data; - - cb->callback (wmxsdk, cb->user_data); - } - g_mutex_unlock (&new_callbacks_mutex); -} - -/****************************************************************/ - -typedef struct { - struct wmxsdk *wmxsdk; - WIMAX_API_DEVICE_STATUS new_status; - WIMAX_API_DEVICE_STATUS old_status; - WIMAX_API_STATUS_REASON reason; - WIMAX_API_CONNECTION_PROGRESS_INFO progress; -} StateChangeInfo; - -static gboolean -state_change_handler(gpointer user_data) -{ - StateChangeInfo *info = user_data; - - if (info->wmxsdk->state_change_cb) { - info->wmxsdk->state_change_cb(info->wmxsdk, - info->new_status, - info->old_status, - info->reason, - info->progress, - info->wmxsdk->callback_data); - } - wmxsdk_unref(info->wmxsdk); - memset(info, 0, sizeof(*info)); - free(info); - return FALSE; -} - -static void -_schedule_state_change(struct wmxsdk *wmxsdk, - WIMAX_API_DEVICE_STATUS new_status, - WIMAX_API_DEVICE_STATUS old_status, - WIMAX_API_STATUS_REASON reason, - WIMAX_API_CONNECTION_PROGRESS_INFO progress) -{ - StateChangeInfo *info; - - info = malloc(sizeof (*info)); - if (!info) - return; - - memset(info, 0, sizeof(*info)); - info->wmxsdk = wmxsdk; - info->new_status = new_status; - info->old_status = old_status; - info->reason = reason; - info->progress = progress; - - wmxsdk_ref(wmxsdk); - g_idle_add(state_change_handler, info); -} - -typedef struct { - struct wmxsdk *wmxsdk; - WIMAX_API_MEDIA_STATUS media_status; -} MediaStatusInfo; - -static gboolean -media_status_change_handler(gpointer user_data) -{ - MediaStatusInfo *info = user_data; - - if (info->wmxsdk->media_status_cb) { - info->wmxsdk->media_status_cb(info->wmxsdk, - info->media_status, - info->wmxsdk->callback_data); - } - wmxsdk_unref(info->wmxsdk); - memset(info, 0, sizeof(*info)); - free(info); - return FALSE; -} - -static void -_schedule_media_status_change(struct wmxsdk *wmxsdk, - WIMAX_API_MEDIA_STATUS media_status) -{ - MediaStatusInfo *info; - - info = malloc(sizeof (*info)); - if (!info) - return; - - memset(info, 0, sizeof(*info)); - info->wmxsdk = wmxsdk; - info->media_status = media_status; - - wmxsdk_ref(wmxsdk); - g_idle_add(media_status_change_handler, info); -} - -typedef struct { - struct wmxsdk *wmxsdk; - WIMAX_API_NETWORK_CONNECTION_RESP result; -} ConnectResultInfo; - -static gboolean -connect_result_handler(gpointer user_data) -{ - ConnectResultInfo *info = user_data; - - if (info->wmxsdk->connect_result_cb) { - info->wmxsdk->connect_result_cb(info->wmxsdk, - info->result, - info->wmxsdk->callback_data); - } - wmxsdk_unref(info->wmxsdk); - memset(info, 0, sizeof(*info)); - free(info); - return FALSE; -} - -static void -_schedule_connect_result(struct wmxsdk *wmxsdk, - WIMAX_API_NETWORK_CONNECTION_RESP resp) -{ - ConnectResultInfo *info; - - info = malloc(sizeof (*info)); - if (!info) - return; - - memset(info, 0, sizeof(*info)); - info->wmxsdk = wmxsdk; - info->result = resp; - - wmxsdk_ref(wmxsdk); - g_idle_add(connect_result_handler, info); -} - -typedef struct { - struct wmxsdk *wmxsdk; - WIMAX_API_NSP_INFO_EX *nsps; - guint num_nsps; -} ScanResultInfo; - -static gboolean -scan_result_handler(gpointer user_data) -{ - ScanResultInfo *info = user_data; - - if (info->wmxsdk->scan_result_cb) { - info->wmxsdk->scan_result_cb(info->wmxsdk, - info->nsps, - info->num_nsps, - info->wmxsdk->callback_data); - } - wmxsdk_unref(info->wmxsdk); - free(info->nsps); - memset(info, 0, sizeof(*info)); - free(info); - return FALSE; -} - -static void -_schedule_scan_result(struct wmxsdk *wmxsdk, - WIMAX_API_NSP_INFO_EX *nsps, - guint num_nsps) -{ - ScanResultInfo *info; - size_t nsps_size; - int i, tmp; - - info = malloc(sizeof (*info)); - if (!info) - return; - - memset(info, 0, sizeof(*info)); - info->wmxsdk = wmxsdk; - - nsps_size = num_nsps * sizeof (WIMAX_API_NSP_INFO_EX); - info->nsps = malloc(nsps_size); - memcpy(info->nsps, nsps, nsps_size); - info->num_nsps = num_nsps; - - /* CAPI may report link quality as zero -- if it does check if it is a bug - * by computing it based on CINR. If it is different, use the computed one. - */ - for (i = 0; i < num_nsps; i++) { - WIMAX_API_NSP_INFO_EX *nsp = &info->nsps[i]; - - if (nsp->linkQuality == 0) { - tmp = cinr_to_percentage(nsp->CINR - 10); - if (tmp != nsp->linkQuality) - nsp->linkQuality = tmp; - } - } - - wmxsdk_ref(wmxsdk); - g_idle_add(scan_result_handler, info); -} - -static gboolean -removed_handler(gpointer user_data) -{ - struct wmxsdk *wmxsdk = user_data; - - if (wmxsdk->removed_cb) - wmxsdk->removed_cb(wmxsdk, wmxsdk->callback_data); - wmxsdk_unref(wmxsdk); - return FALSE; -} - -static void -_schedule_removed(struct wmxsdk *wmxsdk) -{ - wmxsdk_ref(wmxsdk); - g_idle_add(removed_handler, wmxsdk); -} - -/****************************************************************/ - -/* - * Convert a WiMAX API status to an string. - */ -const char *iwmx_sdk_dev_status_to_str(WIMAX_API_DEVICE_STATUS status) -{ - switch (status) { - case WIMAX_API_DEVICE_STATUS_UnInitialized: - return "uninitialized"; - case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW: - return "rf off"; - case WIMAX_API_DEVICE_STATUS_RF_OFF_HW: - return "rf off (hard-block)"; - case WIMAX_API_DEVICE_STATUS_RF_OFF_SW: - return "rf off (soft-block)"; - case WIMAX_API_DEVICE_STATUS_Ready: - return "ready"; - case WIMAX_API_DEVICE_STATUS_Scanning: - return "scanning"; - case WIMAX_API_DEVICE_STATUS_Connecting: - return "connecting"; - case WIMAX_API_DEVICE_STATUS_Data_Connected: - return "connected"; - default: - return "unknown"; - } -} - -const char *iwmx_sdk_reason_to_str(WIMAX_API_STATUS_REASON reason) -{ - switch (reason) { - case WIMAX_API_STATUS_REASON_Normal: - return "normal"; - - /**< Failed to complete NW entry with the selected operator (unspecified reason). */ - case WIMAX_API_STATUS_REASON_Fail_to_connect_to_NW: - return "unspecified failure"; - - /**< Failed to complete ranging */ - case WIMAX_API_STATUS_REASON_Fail_to_connect_Ranging: - return "ranging failed"; - - /**< SBC phase failed */ - case WIMAX_API_STATUS_REASON_Fail_to_connect_SBC: - return "sbc failed"; - - /**< Security error. EAP authentication failed device level */ - case WIMAX_API_STATUS_REASON_Fail_to_connect_EAP_AUTH_Device: - return "EAP device auth failed"; - - /**< Security error. EAP authentication failed user level */ - case WIMAX_API_STATUS_REASON_Fail_to_connect_EAP_AUTH_user: - return "EAP user auth failed"; - - /**< Security error. Handshake failed */ - case WIMAX_API_STATUS_REASON_Fail_to_connect_3_Way_Handshake: - return "3 way handshake failed"; - - /**< Registration failed */ - case WIMAX_API_STATUS_REASON_Fail_to_connect_REG: - return "registration failed"; - - /**< Failed to initialize the data path (failed to perform DSA to one UL and one DL SFs). */ - case WIMAX_API_STATUS_REASON_Fail_to_connect_datapath: - return "datapath failed"; - - default: - return "unknown"; - } -} - -const char *iwmx_sdk_media_status_to_str(WIMAX_API_MEDIA_STATUS status) -{ - switch (status) { - case WIMAX_API_MEDIA_STATUS_LINK_UP: - return "link-up"; - case WIMAX_API_MEDIA_STATUS_LINK_DOWN: - return "link-down"; - case WIMAX_API_MEDIA_STATUS_LINK_RENEW: - return "link-renew"; - default: - return "unknown"; - } -} - -const char * -iwmx_sdk_con_progress_to_str(WIMAX_API_CONNECTION_PROGRESS_INFO progress) -{ - switch (progress) { - - /**< Device is in Ranging */ - case WIMAX_API_DEVICE_CONNECTION_PROGRESS_Ranging: - return "ranging"; - - /**< Device is in SBC */ - case WIMAX_API_DEVICE_CONNECTION_PROGRESS_SBC: - return "sbc"; - - /**< Device is in EAP authentication Device */ - case WIMAX_API_DEVICE_CONNECTION_PROGRESS_EAP_authentication_Device: - return "eap-auth-device"; - - /**< Device is in EAP authentication User */ - case WIMAX_API_DEVICE_CONNECTION_PROGRESS_EAP_authentication_User: - return "eap-auth-user"; - - /**< Device is in 3-way-handshake */ - case WIMAX_API_DEVICE_CONNECTION_PROGRESS_3_way_handshake: - return "3way-handshake"; - - /**< Device is in Registration */ - case WIMAX_API_DEVICE_CONNECTION_PROGRESS_Registration: - return "registration"; - - /**< Device is in De-registration */ - case WIMAX_API_DEVICE_CONNECTION_PROGRESS_De_registration: - return "deregistration"; - - /**< Device is registered (operational) */ - case WIMAX_API_DEVICE_CONNECTION_PROGRESS_Registered: - return "registered"; - - default: - return "unknown"; - } -} - -/* - * Get the device's status from the device - * - * Does NOT cache the result - * Does NOT trigger a state change in NetworkManager - * - * Returns < 0 errno code on error, status code if ok. - */ -static WIMAX_API_DEVICE_STATUS iwmx_sdk_get_device_status(struct wmxsdk *wmxsdk) -{ - WIMAX_API_RET r; - char errstr[512]; - UINT32 errstr_size = sizeof(errstr); - - WIMAX_API_DEVICE_STATUS dev_status; - WIMAX_API_CONNECTION_PROGRESS_INFO pi; - - r = GetDeviceStatus(&wmxsdk->device_id, &dev_status, &pi); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot read device state: %d (%s)", r, errstr); - dev_status = -EIO; - } - return dev_status; -} - -/* - * Get the device's status from the device but return a string describing it - * - * Same conditions as iwmx_sdk_get_device_status(). - */ -static const char *iwmx_sdk_get_device_status_str(struct wmxsdk *wmxsdk) -{ - const char *result; - WIMAX_API_DEVICE_STATUS dev_status; - - dev_status = iwmx_sdk_get_device_status(wmxsdk); - if ((int) dev_status < 0) - result = "cannot read device state"; - else - result = iwmx_sdk_dev_status_to_str(dev_status); - return result; -} - -/* - * If the device is connected but we don't know about the network, - * create the knowledge of it. - * - * Asks the WiMAX API to report which NSP we are connected to and we - * create/update a network_el in the device's network list. Then - * return it. - * - * Returns NULL on error. - * - */ -WIMAX_API_CONNECTED_NSP_INFO_EX *iwmx_sdk_get_connected_network(struct wmxsdk *wmxsdk) -{ - WIMAX_API_CONNECTED_NSP_INFO_EX *nsp_info = NULL; - WIMAX_API_RET r; - char errstr[512]; - UINT32 errstr_size = sizeof(errstr); - - nsp_info = malloc(sizeof (*nsp_info)); - if (!nsp_info) { - nm_log_err(LOGD_WIMAX, "wmxsdk: cannot allocate NSP info"); - return NULL; - } - - r = GetConnectedNSPEx(&wmxsdk->device_id, nsp_info); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot get connected NSP info: %d (%s)", r, errstr); - free (nsp_info); - nsp_info = NULL; - } else { - /* Migth be 0 sometimes; fix that up */ - if (nsp_info->linkQuality == 0) { - int linkq_expected = cinr_to_percentage(nsp_info->CINR - 10); - if (linkq_expected != nsp_info->linkQuality) - nsp_info->linkQuality = linkq_expected; - } - } - - return nsp_info; -} - -/* - * Asks the WiMAX API to report current link statistics. - * - * Returns NULL on error. - * - */ -WIMAX_API_LINK_STATUS_INFO_EX *iwmx_sdk_get_link_status_info(struct wmxsdk *wmxsdk) -{ - WIMAX_API_LINK_STATUS_INFO_EX *stats = NULL; - WIMAX_API_RET r; - char errstr[512]; - UINT32 errstr_size = sizeof(errstr); - - /* Only report if connected */ - if (iwmxsdk_status_get(wmxsdk) < WIMAX_API_DEVICE_STATUS_Connecting) { - nm_log_err(LOGD_WIMAX, "wmxsdk: cannot get link status info unless connected"); - return NULL; - } - - stats = malloc(sizeof (*stats)); - if (!stats) { - nm_log_err(LOGD_WIMAX, "wmxsdk: cannot allocate links status info"); - return NULL; - } - - r = GetLinkStatusEx(&wmxsdk->device_id, stats); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot get link status info: %d (%s)", r, errstr); - free (stats); - stats = NULL; - } - - return stats; -} - -/* - * Callback for a RF State command - * - * Called by the WiMAX API when a command sent to change the RF state - * is completed. This is just a confirmation of what happened with the - * command. - * - * We don't do anything, as when the device changes state, the state - * change callback is called and that will fiddle with the NetworkManager - * internals. - */ -static void __iwmx_sdk_rf_state_cb(WIMAX_API_DEVICE_ID *device_id, - WIMAX_API_RF_STATE rf_state) -{ - nm_log_dbg(LOGD_WIMAX, "rf_state changed to %d", rf_state); -} - -/* - * Turn the radio on or off - * - * First it checks that we are in the right state before doing - * anything; there might be no need to do anything. - * - * Issue a command to the WiMAX API, wait for a callback confirming it - * is done. Sometimes the callback is missed -- in that case, do force - * a state change evaluation. - * - * Frustration note: - * - * Geezoos efing Xist, they make difficult even the most simple - * of the operations - * - * This thing is definitely a pain. If the radio is ON already - * and you switch it on again...well, there is no way to tell - * because you don't get a callback saying it basically - * suceeded. But on the other hand, if the thing was in a - * different state and action needs to be taken, you have to wait - * for a callback to confirm it's done. However, there is also an - * state change callback, which is almost the same, so now you - * have to handle things in two "unrelated" threads of execution. - * - * How the shpx are you expected to tell the difference? Check - * status first? On timeout? Nice gap (eighteen wheeler size) for - * race conditions. - */ -int iwmx_sdk_rf_state_set(struct wmxsdk *wmxsdk, WIMAX_API_RF_STATE rf_state) -{ - int result; - - WIMAX_API_RET r; - char errstr[512]; - UINT32 errstr_size = sizeof(errstr); - WIMAX_API_DEVICE_STATUS dev_status; - - g_assert(rf_state == WIMAX_API_RF_ON || rf_state == WIMAX_API_RF_OFF); - - /* Guess what the current radio state is; if it is ON - * already, don't redo it. */ - dev_status = iwmx_sdk_get_device_status(wmxsdk); - if ((int) dev_status < 0) { - result = dev_status; - goto error_get_status; - } - switch (dev_status) { - case WIMAX_API_DEVICE_STATUS_UnInitialized: - result = -EINVAL; - goto error_cant_do; - case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW: - case WIMAX_API_DEVICE_STATUS_RF_OFF_HW: - nm_log_err(LOGD_WIMAX, "wmxsdk: cannot turn on radio: hw switch is off"); - result = -EPERM; - goto error_cant_do; - break; - case WIMAX_API_DEVICE_STATUS_RF_OFF_SW: - if (rf_state == WIMAX_API_RF_OFF) { - result = 0; - nm_log_dbg(LOGD_WIMAX, "radio is already off"); - goto out_done; - } - break; - case WIMAX_API_DEVICE_STATUS_Ready: - case WIMAX_API_DEVICE_STATUS_Scanning: - case WIMAX_API_DEVICE_STATUS_Connecting: - case WIMAX_API_DEVICE_STATUS_Data_Connected: - if (rf_state == WIMAX_API_RF_ON) { - result = 0; - nm_log_dbg(LOGD_WIMAX, "radio is already on"); - goto out_done; - } - break; - default: - g_assert(1); - } - /* Ok, flip the radio */ - r = CmdControlPowerManagement(&wmxsdk->device_id, rf_state); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot flip radio to %d: %d (%s) [device is in state %s]", - rf_state, r, errstr, iwmx_sdk_get_device_status_str(wmxsdk)); - result = -EIO; - } else - result = -EINPROGRESS; -out_done: -error_cant_do: -error_get_status: - return result; -} - -/* - * Read the cached device status - */ -WIMAX_API_DEVICE_STATUS iwmxsdk_status_get(struct wmxsdk *wmxsdk) -{ - WIMAX_API_DEVICE_STATUS status; - - g_mutex_lock(&wmxsdk->status_mutex); - status = wmxsdk->status; - g_mutex_unlock(&wmxsdk->status_mutex); - return status; -} - -/* - * Callback for a Connect command - * - * Called by the WiMAX API when a command sent to connect is - * completed. This is just a confirmation of what happened with the - * command. - * - * WE DON'T DO MUCH HERE -- the real meat happens when a state change - * callback is sent, where we detect we move to connected state (or - * from disconnecting to something else); the state change callback is - * called and that will fiddle with the NetworkManager internals. - */ -static void __iwmx_sdk_connect_cb(WIMAX_API_DEVICE_ID *device_id, - WIMAX_API_NETWORK_CONNECTION_RESP resp) -{ - WIMAX_API_DEVICE_STATUS status; - struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id); - - status = iwmxsdk_status_get(wmxsdk); - if (resp == WIMAX_API_CONNECTION_SUCCESS) { - if (status != WIMAX_API_DEVICE_STATUS_Data_Connected) { - nm_log_err(LOGD_WIMAX, "wmxsdk: error: connect worked, but state" - " didn't change (now it is %d [%s])", - status, - iwmx_sdk_dev_status_to_str(status)); - } - } else { - nm_log_err(LOGD_WIMAX, "wmxsdk: failed to connect (status %d: %s)", - status, iwmx_sdk_dev_status_to_str(status)); - } - - _schedule_connect_result(wmxsdk, resp); -} - -/* - * Connect to a network - * - * This function starts the connection process to a given network; - * when the device changes status, the status change callback will - * tell NetworkManager if the network is finally connected or not. - * - * One of the reasons it is done like that is to allow external tools - * to control the device and the plugin just passing the status so - * NetworkManager displays the right info. - */ -int iwmx_sdk_connect(struct wmxsdk *wmxsdk, const char *nsp_name) -{ - int result = 0; - - WIMAX_API_RET r; - char errstr[512]; - UINT32 errstr_size = sizeof(errstr); - WIMAX_API_DEVICE_STATUS dev_status; - char sdk_name[MAX_SIZE_OF_NSP_NAME]; - - g_mutex_lock(&wmxsdk->connect_mutex); - /* Guess what the current radio state is; if it is ON - * already, don't redo it. */ - dev_status = iwmxsdk_status_get(wmxsdk); - if ((int) dev_status < 0) { - result = dev_status; - goto error_get_status; - } - switch (dev_status) { - case WIMAX_API_DEVICE_STATUS_UnInitialized: - nm_log_err(LOGD_WIMAX, "wmxsdk: SW BUG? HW is uninitialized"); - result = -EINVAL; - goto error_cant_do; - case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW: - case WIMAX_API_DEVICE_STATUS_RF_OFF_HW: - case WIMAX_API_DEVICE_STATUS_RF_OFF_SW: - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot connect: radio is off"); - result = -EPERM; - goto error_cant_do; - case WIMAX_API_DEVICE_STATUS_Ready: - case WIMAX_API_DEVICE_STATUS_Scanning: - break; - case WIMAX_API_DEVICE_STATUS_Connecting: - nm_log_dbg(LOGD_WIMAX, "Connect already pending, waiting for it"); - result = -EINPROGRESS; - goto error_cant_do; - case WIMAX_API_DEVICE_STATUS_Data_Connected: - nm_log_err(LOGD_WIMAX, "wmxsdk: BUG? need to disconnect?"); - result = -EINVAL; - goto error_cant_do; - default: - g_assert(1); - } - - /* The SDK treats the network name as wchar_t* while the contents are - * actually just UTF-8... WTF? Hand it a full buffer to work around - * boundary cases where the NSP name contains an odd # of characters. - */ - memset(sdk_name, 0, sizeof (sdk_name)); - memcpy(sdk_name, nsp_name, strlen (nsp_name)); - - /* Ok, do the connection, wait for a callback */ - r = CmdConnectToNetwork(&wmxsdk->device_id, &sdk_name[0], 0, 0); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot connect to network %s: %d (%s) - device is in state '%s'", - nsp_name, r, errstr, - iwmx_sdk_get_device_status_str(wmxsdk)); - result = -EIO; - } - -error_cant_do: -error_get_status: - g_mutex_unlock(&wmxsdk->connect_mutex); - return result; -} - -/* - * Callback for a Disconnect command - * - * Called by the WiMAX API when a command sent to connect is - * completed. This is just a confirmation of what happened with the - * command. - * - * When the device changes state, the state change callback is called - * and that will fiddle with the NetworkManager internals. - * - * We just update the result of the command and wake up anybody who is - * waiting for this conditional variable. - */ -static void __iwmx_sdk_disconnect_cb(WIMAX_API_DEVICE_ID *device_id, - WIMAX_API_NETWORK_CONNECTION_RESP resp) -{ - struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id); - WIMAX_API_DEVICE_STATUS status; - - status = iwmxsdk_status_get(wmxsdk); - if (resp == WIMAX_API_CONNECTION_SUCCESS) { - if (status == WIMAX_API_DEVICE_STATUS_Data_Connected) { - nm_log_err(LOGD_WIMAX, "wmxsdk: error: disconnect worked, " - "but state didn't change (now it is %d [%s])", status, - iwmx_sdk_dev_status_to_str(status)); - } - } else - nm_log_err(LOGD_WIMAX, "wmxsdk: failed to disconnect (status %d: %s)", - status, iwmx_sdk_dev_status_to_str(status)); -} - -/* - * Disconnect from a network - * - * This function tells the device to disconnect; the state change - * callback will take care of inform NetworkManager's internals. - */ -int iwmx_sdk_disconnect(struct wmxsdk *wmxsdk) -{ - int result; - - WIMAX_API_RET r; - char errstr[512]; - UINT32 errstr_size = sizeof(errstr); - WIMAX_API_DEVICE_STATUS dev_status; - - g_mutex_lock(&wmxsdk->connect_mutex); - /* Guess what the current radio state is; if it is ON - * already, don't redo it. */ - dev_status = iwmx_sdk_get_device_status(wmxsdk); - if ((int) dev_status < 0) { - result = dev_status; - goto error_get_status; - } - switch (dev_status) { - case WIMAX_API_DEVICE_STATUS_UnInitialized: - nm_log_err(LOGD_WIMAX, "wmxsdk: SW BUG? HW is uninitialized"); - result = -EINVAL; - goto error_cant_do; - case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW: - case WIMAX_API_DEVICE_STATUS_RF_OFF_HW: - case WIMAX_API_DEVICE_STATUS_RF_OFF_SW: - nm_log_dbg(LOGD_WIMAX, "Cannot disconnect, radio is off; ignoring"); - result = 0; - goto error_cant_do; - case WIMAX_API_DEVICE_STATUS_Ready: - case WIMAX_API_DEVICE_STATUS_Scanning: - nm_log_dbg(LOGD_WIMAX, "Cannot disconnect, already disconnected; ignoring"); - result = 0; - goto error_cant_do; - case WIMAX_API_DEVICE_STATUS_Connecting: - case WIMAX_API_DEVICE_STATUS_Data_Connected: - break; - default: - g_assert(1); - } - /* Ok, flip the radio */ - r = CmdDisconnectFromNetwork(&wmxsdk->device_id); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot disconnect from network: %d (%s)", r, errstr); - result = -EIO; - } else - result = -EINPROGRESS; -error_cant_do: -error_get_status: - g_mutex_unlock(&wmxsdk->connect_mutex); - return result; -} - -/* - * Turn fast reconnect capability on/off - * - * This function tells wimaxd to turn fast reconnect on or off. - */ -int iwmx_sdk_set_fast_reconnect_enabled(struct wmxsdk *wmxsdk, int enabled) -{ - WIMAX_API_RET r; - char errstr[512]; - UINT32 errstr_size = sizeof(errstr); - - r = SetFastReconnectCapabilityStatus(&wmxsdk->device_id, !!enabled); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot set fast reconnect to %d: %d (%s)", - enabled, r, errstr); - return -EIO; - } - return 0; -} - -static void __iwmx_sdk_media_status_update_cb (WIMAX_API_DEVICE_ID_P device_id, - WIMAX_API_MEDIA_STATUS mediaStatus) -{ - struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id); - - /* Ignore redundant LINK_UP events */ - if ( mediaStatus == WIMAX_API_MEDIA_STATUS_LINK_UP - && wmxsdk->media_status == WIMAX_API_MEDIA_STATUS_LINK_UP) - return; - - wmxsdk->media_status = mediaStatus; - - nm_log_dbg(LOGD_WIMAX, "wmxsdk: media status change to (%d) %s", - mediaStatus, iwmx_sdk_media_status_to_str (mediaStatus)); - - _schedule_media_status_change(wmxsdk, mediaStatus); -} - -/* - * Callback for state change messages - * - * Just pass them to the state transition handler - */ -static void __iwmx_sdk_state_change_cb(WIMAX_API_DEVICE_ID *device_id, - WIMAX_API_DEVICE_STATUS status, - WIMAX_API_STATUS_REASON reason, - WIMAX_API_CONNECTION_PROGRESS_INFO pi) -{ - struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id); - WIMAX_API_DEVICE_STATUS old_status; - - nm_log_dbg(LOGD_WIMAX, "wmxsdk: state change to (%d) %s reason (%d) %s", - status, iwmx_sdk_dev_status_to_str (status), - reason, iwmx_sdk_reason_to_str (reason)); - - g_mutex_lock(&wmxsdk->status_mutex); - old_status = wmxsdk->status; - wmxsdk->status = status; - g_mutex_unlock(&wmxsdk->status_mutex); - - _schedule_state_change(wmxsdk, status, old_status, reason, pi); -} - -/* - * Called by _iwmx_sdk_*scan_cb() when [wide or preferred] scan results - * are available. - * - * From here we update NetworkManager's idea of which networks are available. - */ -static void __iwmx_sdk_scan_common_cb(WIMAX_API_DEVICE_ID *device_id, - WIMAX_API_NSP_INFO_EX *nsp_list, - UINT32 nsp_list_size) -{ - struct wmxsdk *wmxsdk = deviceid_to_wmxsdk(device_id); - - g_mutex_lock(&wmxsdk->network_mutex); - _schedule_scan_result(wmxsdk, nsp_list, nsp_list_size); - g_mutex_unlock(&wmxsdk->network_mutex); -} - -/* - * Called by the WiMAX API when we get a wide scan result - * - * We treat them same as wide, so we just call that. - */ -static void __iwmx_sdk_wide_scan_cb(WIMAX_API_DEVICE_ID *device_id, - WIMAX_API_NSP_INFO_EX *nsp_list, - UINT32 nsp_list_size) -{ - __iwmx_sdk_scan_common_cb(device_id, nsp_list, nsp_list_size); -} - -/* - * Called by the WiMAX API when we get a normal (non wide) scan result - * - * We treat them same as wide, so we just call that. - */ -static void __iwmx_sdk_scan_cb(WIMAX_API_DEVICE_ID *device_id, - WIMAX_API_NSP_INFO_EX *nsp_list, - UINT32 nsp_list_size, UINT32 searchProgress) -{ - __iwmx_sdk_scan_common_cb(device_id, nsp_list, nsp_list_size); -} - -/* - * Called to ask the device to scan for networks - * - * We don't really scan as the WiMAX SDK daemon scans in the - * background for us. We just get the results and hand them back via - * the scan_result_cb callback. - */ -int iwmx_sdk_get_networks(struct wmxsdk *wmxsdk) -{ - int result; - - UINT32 nsp_list_length = 10; - WIMAX_API_NSP_INFO_EX nsp_list[10]; /* FIXME: up to 32? */ - - WIMAX_API_RET r; - char errstr[512]; - UINT32 errstr_size = sizeof(errstr); - - r = GetNetworkListEx(&wmxsdk->device_id, nsp_list, &nsp_list_length); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot get network list: %d (%s)", r, errstr); - result = -EIO; - goto error_scan; - } - - if (nsp_list_length == 0) { - nm_log_dbg(LOGD_WIMAX, "no networks"); - } else - __iwmx_sdk_scan_common_cb(&wmxsdk->device_id, nsp_list, - nsp_list_length); - result = 0; -error_scan: - return result; -} - -/* - * Initialize the WiMAX API, register with it, setup callbacks - * - */ -static int iwmx_sdk_setup(struct wmxsdk *wmxsdk) -{ - int result, status; - - WIMAX_API_RET r; - - char errstr[512]; - UINT32 errstr_size = sizeof(errstr); - - result = -ENFILE; - - /* device_id initialized by iwmx_sdk_dev_add */ - - r = WiMaxDeviceOpen(&wmxsdk->device_id); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot open device: %d (%s)", r, errstr); - goto error_wimaxdeviceopen; - } - - /* - * We scan in auto mode (in the background) - * - * Otherwise is messy -- if we have NetworkManager triggering a scan - * when we call iwmx_nm_scan() -> iwmx_sdk_scan(), most of the - * times that causes a race condition when the UI asks for a - * scan right before displaying the network menu. As there is - * no way to cancel an ongoing scan before connecting, we are - * stuck. So we do auto bg and have iwmx_sdk_scan() just return - * the current network list. - */ - r = SetConnectionMode(&wmxsdk->device_id, - WIMAX_API_CONNECTION_AUTO_SCAN_MANUAL_CONNECT); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot set connectin mode to manual: %d (%s)", r, errstr); - goto error_connection_mode; - } - - r = SubscribeControlPowerManagement(&wmxsdk->device_id, - __iwmx_sdk_rf_state_cb); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot subscribe to radio change events: %u (%s)", r, errstr); - result = -EIO; - goto error_subscribe_rf_state; - } - - r = SubscribeDeviceStatusChange(&wmxsdk->device_id, - __iwmx_sdk_state_change_cb); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot subscribe to state chaneg events: %d (%s)", r, errstr); - goto error_subscribe_state_change; - } - - r = SubscribeNetworkSearchWideScanEx(&wmxsdk->device_id, - __iwmx_sdk_wide_scan_cb); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot subscribe to wide scan events: %d (%s)", r, errstr); - goto error_subscribe_wide_scan; - } - r = SubscribeNetworkSearchEx(&wmxsdk->device_id, __iwmx_sdk_scan_cb); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot subscribe to scan events: %d (%s)", r, errstr); - goto error_subscribe_scan; - } - - r = SubscribeConnectToNetwork(&wmxsdk->device_id, - __iwmx_sdk_connect_cb); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot subscribe to connect events: %d (%s)", r, errstr); - goto error_subscribe_connect; - } - - r = SubscribeDisconnectToNetwork(&wmxsdk->device_id, - __iwmx_sdk_disconnect_cb); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot subscribe to disconnect events: %d (%s)", r, errstr); - goto error_subscribe_disconnect; - } - - r = SubscribeMediaStatusUpdate(&wmxsdk->device_id, __iwmx_sdk_media_status_update_cb); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&wmxsdk->device_id, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot subscribe to media status events: %d (%s)", r, errstr); - goto error_subscribe_media_status; - } - - status = iwmx_sdk_get_device_status(wmxsdk); - if ((int) status < 0) - status = WIMAX_API_DEVICE_STATUS_UnInitialized; - - g_mutex_lock(&wmxsdk->status_mutex); - wmxsdk->status = status; - g_mutex_unlock(&wmxsdk->status_mutex); - - _schedule_state_change(wmxsdk, - status, - WIMAX_API_DEVICE_STATUS_UnInitialized, - WIMAX_API_STATUS_REASON_Normal, - WIMAX_API_DEVICE_CONNECTION_PROGRESS_Ranging); - - return 0; - - UnsubscribeMediaStatusUpdate(&wmxsdk->device_id); -error_subscribe_media_status: - UnsubscribeDisconnectToNetwork(&wmxsdk->device_id); -error_subscribe_disconnect: - UnsubscribeConnectToNetwork(&wmxsdk->device_id); -error_subscribe_connect: - UnsubscribeNetworkSearchEx(&wmxsdk->device_id); -error_subscribe_scan: - UnsubscribeNetworkSearchWideScanEx(&wmxsdk->device_id); -error_subscribe_wide_scan: - UnsubscribeDeviceStatusChange(&wmxsdk->device_id); -error_subscribe_state_change: - UnsubscribeControlPowerManagement(&wmxsdk->device_id); -error_subscribe_rf_state: -error_connection_mode: - WiMaxDeviceClose(&wmxsdk->device_id); -error_wimaxdeviceopen: - return result; -} - -/* - * Called when a device is torn down - * - * Cleanup all that is done in iwmx_sdk_setup(). Remove callbacks, - * unregister from the WiMAX API. - */ -static void iwmx_sdk_remove(struct wmxsdk *wmxsdk) -{ - UnsubscribeMediaStatusUpdate(&wmxsdk->device_id); - UnsubscribeDisconnectToNetwork(&wmxsdk->device_id); - UnsubscribeConnectToNetwork(&wmxsdk->device_id); - UnsubscribeNetworkSearchEx(&wmxsdk->device_id); - UnsubscribeNetworkSearchWideScanEx(&wmxsdk->device_id); - UnsubscribeDeviceStatusChange(&wmxsdk->device_id); - UnsubscribeControlPowerManagement(&wmxsdk->device_id); - WiMaxDeviceClose(&wmxsdk->device_id); -} - -void iwmx_sdk_set_callbacks(struct wmxsdk *wmxsdk, - WimaxStateChangeFunc state_change_cb, - WimaxMediaStatusFunc media_status_cb, - WimaxConnectResultFunc connect_result_cb, - WimaxScanResultFunc scan_result_cb, - WimaxRemovedFunc removed_cb, - void *user_data) -{ - wmxsdk->state_change_cb = state_change_cb; - wmxsdk->media_status_cb = media_status_cb; - wmxsdk->connect_result_cb = connect_result_cb; - wmxsdk->scan_result_cb = scan_result_cb; - wmxsdk->removed_cb = removed_cb; - wmxsdk->callback_data = user_data; -} - -/* Initialize a [zeroed] struct wmxsdk */ -static struct wmxsdk *wmxsdk_new(void) -{ - struct wmxsdk *wmxsdk; - - wmxsdk = malloc(sizeof(*wmxsdk)); - if (wmxsdk) { - memset(wmxsdk, 0, sizeof(*wmxsdk)); - - wmxsdk->refcount = 1; - g_mutex_init(&wmxsdk->network_mutex); - - wmxsdk->status = WIMAX_API_DEVICE_STATUS_UnInitialized; - g_mutex_init(&wmxsdk->status_mutex); - - g_mutex_init(&wmxsdk->connect_mutex); - } - return wmxsdk; -} - -struct wmxsdk *wmxsdk_ref(struct wmxsdk *wmxsdk) -{ - g_atomic_int_add(&wmxsdk->refcount, 1); - return wmxsdk; -} - -void wmxsdk_unref(struct wmxsdk *wmxsdk) -{ - if (g_atomic_int_dec_and_test(&wmxsdk->refcount)) { - g_mutex_clear(&wmxsdk->status_mutex); - g_mutex_clear(&wmxsdk->connect_mutex); - memset(wmxsdk, 0, sizeof(*wmxsdk)); - free(wmxsdk); - } -} - -static void iwmx_sdk_dev_add(unsigned idx, unsigned api_idx, const char *name) -{ - struct wmxsdk *wmxsdk; - const char *s; - - if (idx >= IWMX_SDK_DEV_MAX) { - nm_log_err(LOGD_WIMAX, "BUG! idx (%u) >= IWMX_SDK_DEV_MAX (%u)", idx, IWMX_SDK_DEV_MAX); - return; - } - if (g_iwmx_sdk_devs[idx] != NULL) { - nm_log_err(LOGD_WIMAX, "BUG! device index %u already enumerated?", idx); - return; - } - - wmxsdk = wmxsdk_new(); - if (wmxsdk == NULL) { - nm_log_err(LOGD_WIMAX, "Can't allocate %zu bytes", sizeof(*wmxsdk)); - return; - } - - /* - * This depends on a hack in the WiMAX Network Service; it has - * to return, as part of the device name, a string "if:IFNAME" - * where the OS's device name is stored. - */ - s = strstr(name, "if:"); - if (s == NULL - || sscanf(s, "if:%15[^ \f\n\r\t\v]", wmxsdk->ifname) != 1) { - nm_log_err(LOGD_WIMAX, "Cannot extract network interface name off '%s'", - name); - goto error; - } - nm_log_dbg(LOGD_WIMAX, "network interface name: '%s'", wmxsdk->ifname); - - strncpy(wmxsdk->name, name, sizeof(wmxsdk->name)); - wmxsdk->device_id.privilege = WIMAX_API_PRIVILEGE_READ_WRITE; - wmxsdk->device_id.deviceIndex = api_idx; - - if (iwmx_sdk_setup(wmxsdk) != 0) { - nm_log_err(LOGD_WIMAX, "wxmsdk: %s: cannot set up interface", wmxsdk->ifname); - goto error; - } - - g_iwmx_sdk_devs[idx] = wmxsdk; - - /* Notify listeners of new devices */ - iwmx_sdk_call_new_callbacks (wmxsdk); - return; - -error: - wmxsdk_unref(wmxsdk); - return; -} - -static void iwmx_sdk_dev_rm(unsigned idx) -{ - struct wmxsdk *wmxsdk; - - if (idx >= IWMX_SDK_DEV_MAX) { - nm_log_err(LOGD_WIMAX, "BUG! idx (%u) >= IWMX_SDK_DEV_MAX (%u)", idx, IWMX_SDK_DEV_MAX); - return; - } - - wmxsdk = g_iwmx_sdk_devs[idx]; - _schedule_removed(wmxsdk); - iwmx_sdk_remove(wmxsdk); - wmxsdk_unref(wmxsdk); - g_iwmx_sdk_devs[idx] = NULL; -} - -static void iwmx_sdk_addremove_cb(WIMAX_API_DEVICE_ID *devid, - BOOL presence) -{ - unsigned int cnt; - WIMAX_API_RET r; - WIMAX_API_HW_DEVICE_ID device_id_list[5]; - UINT32 device_id_list_size = ARRAY_SIZE(device_id_list); - char errstr[512]; - UINT32 errstr_size = sizeof(errstr); - - g_mutex_lock(&add_remove_mutex); - - nm_log_dbg(LOGD_WIMAX, "cb: handle %u index #%u is %d", devid->sdkHandle, - devid->deviceIndex, presence); - - r = GetListDevice(devid, device_id_list, &device_id_list_size); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(devid, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot obtain list of devices: %d (%s)", r, errstr); - goto out; - } - - if (device_id_list_size == 0) { - nm_log_dbg(LOGD_WIMAX, "No WiMAX devices reported"); - } else { - for (cnt = 0; cnt < device_id_list_size; cnt++) { - WIMAX_API_HW_DEVICE_ID *dev = - device_id_list + cnt; - nm_log_dbg(LOGD_WIMAX, "#%u index #%u device %s", cnt, - dev->deviceIndex, dev->deviceName); - } - } - - if (presence) { - WIMAX_API_HW_DEVICE_ID *dev; - - /* Make sure the wimax NS isn't lying to us */ - if (device_id_list_size < devid->deviceIndex) { - nm_log_err(LOGD_WIMAX, "wmxsdk: changed device (%u) not in the list? (%u items)", - devid->deviceIndex, device_id_list_size); - goto out; - } - - /* Add the device to our internal list */ - dev = device_id_list + devid->deviceIndex; - iwmx_sdk_dev_add(devid->deviceIndex, dev->deviceIndex, dev->deviceName); - } else { - /* Remove the device from our internal list */ - int idx = deviceid_to_index(devid); - - if (idx >= 0) - iwmx_sdk_dev_rm(idx); - } - -out: - g_mutex_unlock(&add_remove_mutex); -} - -/* - * Initialize the WiMAX API, register with it, setup callbacks for - * device coming up / dissapearing - */ -int iwmx_sdk_api_init(void) -{ - int result; - unsigned int cnt; - WIMAX_API_RET r; - char errstr[512]; - UINT32 errstr_size = sizeof(errstr); - - WIMAX_API_HW_DEVICE_ID device_id_list[5]; - UINT32 device_id_list_size = ARRAY_SIZE(device_id_list); - - memset(&g_api, 0, sizeof(g_api)); - g_api.privilege = WIMAX_API_PRIVILEGE_READ_WRITE; - - result = -EIO; - r = WiMaxAPIOpen(&g_api); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&g_api, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: WiMaxAPIOpen failed with %d (%s)", r, errstr); - goto error_wimaxapiopen; - } - - r = SubscribeDeviceInsertRemove(&g_api, iwmx_sdk_addremove_cb); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&g_api, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: insert/remove subscribe failed with %d (%s)", r, errstr); - goto error_close; - } - - r = GetListDevice(&g_api, device_id_list, &device_id_list_size); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&g_api, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: Cannot obtain list of devices: %d (%s)", r, errstr); - goto error_close; - } - if (device_id_list_size < g_api.deviceIndex) { - nm_log_err(LOGD_WIMAX, "wmxsdk: changed device (%u) not in the list? (%u items)", - g_api.deviceIndex, device_id_list_size); - } - - if (device_id_list_size == 0) { - nm_log_dbg(LOGD_WIMAX, "No WiMAX devices reported"); - } else { - for (cnt = 0; cnt < device_id_list_size; cnt++) { - WIMAX_API_HW_DEVICE_ID *dev = device_id_list + cnt; - nm_log_dbg(LOGD_WIMAX, "#%u index #%u device %s", cnt, dev->deviceIndex, dev->deviceName); - iwmx_sdk_dev_add(cnt, dev->deviceIndex, dev->deviceName); - } - } - return 0; - -error_close: - WiMaxAPIClose(&g_api); -error_wimaxapiopen: - return result; -} - -void iwmx_sdk_api_exit(void) -{ - WIMAX_API_RET r; - - char errstr[512]; - UINT32 errstr_size = sizeof(errstr); - - r = WiMaxAPIClose(&g_api); - if (r != WIMAX_API_RET_SUCCESS) { - GetErrorString(&g_api, r, errstr, &errstr_size); - nm_log_err(LOGD_WIMAX, "wmxsdk: WiMaxAPIClose failed with %d (%s)", r, errstr); - } - return; -} diff --git a/src/devices/wimax/iwmxsdk.h b/src/devices/wimax/iwmxsdk.h deleted file mode 100644 index c8e76696..00000000 --- a/src/devices/wimax/iwmxsdk.h +++ /dev/null @@ -1,112 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* - * - * Copyright (C) 2011 Red Hat, Inc. All rights reserved. - * Copyright (C) 2007-2010 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef __IWMXSDK_H__ -#define __IWMXSDK_H__ - -#include "nm-wimax-util.h" - -#include -#include - -struct wmxsdk; - -typedef void (*WimaxNewWmxsdkFunc) (struct wmxsdk *wmxsdk, void *user_data); - -typedef void (*WimaxStateChangeFunc) (struct wmxsdk *wmxsdk, - WIMAX_API_DEVICE_STATUS new_status, - WIMAX_API_DEVICE_STATUS old_status, - WIMAX_API_STATUS_REASON reason, - WIMAX_API_CONNECTION_PROGRESS_INFO info, - void *user_data); - -typedef void (*WimaxMediaStatusFunc) (struct wmxsdk *wmxsdk, - WIMAX_API_MEDIA_STATUS media_status, - void *user_data); - -typedef void (*WimaxConnectResultFunc) (struct wmxsdk *wmxsdk, - WIMAX_API_NETWORK_CONNECTION_RESP resp, - void *user_data); - -typedef void (*WimaxScanResultFunc) (struct wmxsdk *wmxsdk, - WIMAX_API_NSP_INFO_EX *nsps, - guint num_nsps, - void *user_data); - -typedef void (*WimaxRemovedFunc) (struct wmxsdk *wmxsdk, void *user_data); - -struct wmxsdk { - gint refcount; - - WIMAX_API_DEVICE_ID device_id; - - WimaxStateChangeFunc state_change_cb; - WimaxMediaStatusFunc media_status_cb; - WimaxConnectResultFunc connect_result_cb; - WimaxScanResultFunc scan_result_cb; - WimaxRemovedFunc removed_cb; - void *callback_data; - - GMutex network_mutex; - - WIMAX_API_DEVICE_STATUS status; - WIMAX_API_MEDIA_STATUS media_status; - GMutex status_mutex; - - GMutex connect_mutex; - - char name[100]; - char ifname[16]; -}; - -struct wmxsdk *iwmx_sdk_get_wmxsdk_for_iface(const char *iface); - -struct wmxsdk *wmxsdk_ref(struct wmxsdk *wmxsdk); -void wmxsdk_unref(struct wmxsdk *wmxsdk); - -/* Register/unregister callbacks when a new wmxsdk is set up */ -void iwmx_sdk_new_callback_register(WimaxNewWmxsdkFunc callback, void *user_data); -void iwmx_sdk_new_callback_unregister(WimaxNewWmxsdkFunc callback, void *user_data); - -void iwmx_sdk_set_callbacks(struct wmxsdk *wmxsdk, - WimaxStateChangeFunc state_change_cb, - WimaxMediaStatusFunc media_status_func, - WimaxConnectResultFunc connect_result_cb, - WimaxScanResultFunc scan_result_cb, - WimaxRemovedFunc removed_cb, - void *user_data); - -WIMAX_API_DEVICE_STATUS iwmxsdk_status_get(struct wmxsdk *wmxsdk); -int iwmx_sdk_connect(struct wmxsdk *wmxsdk, const char *nsp_name); -int iwmx_sdk_disconnect(struct wmxsdk *wmxsdk); -int iwmx_sdk_set_fast_reconnect_enabled(struct wmxsdk *wmxsdk, int enabled); -WIMAX_API_CONNECTED_NSP_INFO_EX *iwmx_sdk_get_connected_network(struct wmxsdk *wmxsdk); -WIMAX_API_LINK_STATUS_INFO_EX *iwmx_sdk_get_link_status_info(struct wmxsdk *wmxsdk); -const char *iwmx_sdk_dev_status_to_str(WIMAX_API_DEVICE_STATUS status); -const char *iwmx_sdk_reason_to_str(WIMAX_API_STATUS_REASON reason); -const char *iwmx_sdk_media_status_to_str(WIMAX_API_MEDIA_STATUS status); -const char *iwmx_sdk_con_progress_to_str(WIMAX_API_CONNECTION_PROGRESS_INFO progress); -int iwmx_sdk_rf_state_set(struct wmxsdk *wmxsdk, WIMAX_API_RF_STATE rf_state); -int iwmx_sdk_get_networks(struct wmxsdk *wmxsdk); -int iwmx_sdk_api_init(void); -void iwmx_sdk_api_exit(void); - -#endif /* __IWMXSDK_H__ */ diff --git a/src/devices/wimax/nm-device-wimax.c b/src/devices/wimax/nm-device-wimax.c deleted file mode 100644 index 0c8f1cbb..00000000 --- a/src/devices/wimax/nm-device-wimax.c +++ /dev/null @@ -1,1416 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2010 - 2011 Red Hat, Inc. - * Copyright (C) 2009 Novell, Inc. - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include - -#include "nm-wimax-util.h" - -#include -#include - -#include "nm-device-wimax.h" -#include "nm-wimax-util.h" -#include "nm-logging.h" -#include "nm-device-private.h" -#include "NetworkManagerUtils.h" -#include "nm-active-connection.h" -#include "nm-dbus-manager.h" -#include "nm-connection.h" -#include "nm-platform.h" -#include "nm-setting-connection.h" -#include "nm-setting-wimax.h" -#include "nm-utils.h" -#include "nm-rfkill-manager.h" -#include "iwmxsdk.h" -#include "nm-enum-types.h" -#include "nm-dbus-glib-types.h" - -static gboolean impl_device_get_nsp_list (NMDeviceWimax *device, GPtrArray **list, GError **error); - -#include "nm-device-wimax-glue.h" - -G_DEFINE_TYPE (NMDeviceWimax, nm_device_wimax, NM_TYPE_DEVICE) - -enum { - PROP_0, - PROP_NSPS, - PROP_ACTIVE_NSP, - PROP_CENTER_FREQ, - PROP_RSSI, - PROP_CINR, - PROP_TX_POWER, - PROP_BSID, - - LAST_PROP -}; - -enum { - NSP_ADDED, - NSP_REMOVED, - - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -#define NM_DEVICE_WIMAX_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ - NM_TYPE_DEVICE_WIMAX, \ - NMDeviceWimaxPrivate)) - -typedef struct { - gboolean disposed; - - struct wmxsdk *sdk; - WIMAX_API_DEVICE_STATUS status; - gboolean connect_failed; - - gboolean enabled; - gboolean wimaxd_enabled; - guint activation_timeout_id; - - /* Track whether stage1 (Prepare) is completed yet or not */ - gboolean prepare_done; - - guint sdk_action_defer_id; - - guint link_timeout_id; - guint poll_id; - - GSList *nsp_list; - NMWimaxNsp *current_nsp; - - /* interesting stuff when connected */ - guint center_freq; - gint rssi; - gint cinr; - gint tx_power; - char *bsid; -} NMDeviceWimaxPrivate; - -/***********************************************************/ - -static gboolean -impl_device_get_nsp_list (NMDeviceWimax *self, GPtrArray **nsps, GError **error) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - GSList *iter; - - *nsps = g_ptr_array_sized_new (4); - for (iter = priv->nsp_list; iter; iter = iter->next) - g_ptr_array_add (*nsps, g_strdup (nm_wimax_nsp_get_dbus_path (NM_WIMAX_NSP (iter->data)))); - - return TRUE; -} - -static void -set_current_nsp (NMDeviceWimax *self, NMWimaxNsp *new_nsp) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - NMWimaxNsp *old_nsp; - gboolean path_changed = FALSE; - - old_nsp = priv->current_nsp; - priv->current_nsp = NULL; - - if (new_nsp) - priv->current_nsp = g_object_ref (new_nsp); - - if (old_nsp && new_nsp) { - path_changed = (g_strcmp0 (nm_wimax_nsp_get_dbus_path (old_nsp), - nm_wimax_nsp_get_dbus_path (new_nsp)) != 0); - } - - /* Only notify if it's really changed */ - if (old_nsp != new_nsp || path_changed) - g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_ACTIVE_NSP); - - if (old_nsp) - g_object_unref (old_nsp); -} - -static gboolean -activation_timed_out (gpointer data) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (data); - - priv->activation_timeout_id = 0; - nm_device_state_changed (NM_DEVICE (data), NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - - return FALSE; -} - -static void -emit_nsp_added_removed (NMDeviceWimax *self, - guint signum, - NMWimaxNsp *nsp, - gboolean recheck_available_connections) -{ - g_signal_emit (self, signals[signum], 0, nsp); - g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_NSPS); - nm_device_emit_recheck_auto_activate (NM_DEVICE (self)); - if (recheck_available_connections) - nm_device_recheck_available_connections (NM_DEVICE (self)); -} - -static void -remove_all_nsps (NMDeviceWimax *self) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - - set_current_nsp (self, NULL); - - while (priv->nsp_list) { - NMWimaxNsp *nsp = NM_WIMAX_NSP (priv->nsp_list->data); - - priv->nsp_list = g_slist_remove (priv->nsp_list, nsp); - emit_nsp_added_removed (self, NSP_REMOVED, nsp, FALSE); - g_object_unref (nsp); - } - - nm_device_recheck_available_connections (NM_DEVICE (self)); -} - -static NMWimaxNsp * -get_nsp_by_name (NMDeviceWimax *self, const char *name) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - GSList *iter; - - g_return_val_if_fail (name, NULL); - - for (iter = priv->nsp_list; iter; iter = iter->next) { - NMWimaxNsp *nsp = NM_WIMAX_NSP (iter->data); - - if (!g_strcmp0 (nm_wimax_nsp_get_name (nsp), name)) - return nsp; - } - - return NULL; -} - -static NMWimaxNsp * -get_nsp_by_path (NMDeviceWimax *self, const char *path) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - GSList *iter; - - g_return_val_if_fail (path, NULL); - - for (iter = priv->nsp_list; iter; iter = iter->next) { - NMWimaxNsp *nsp = NM_WIMAX_NSP (iter->data); - - if (!strcmp (nm_wimax_nsp_get_dbus_path (nsp), path)) - return nsp; - } - - return NULL; -} - -static gboolean -update_availability (NMDeviceWimax *self, gboolean old_available) -{ - NMDevice *device = NM_DEVICE (self); - NMDeviceState state; - gboolean new_available, changed = FALSE; - - new_available = nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); - if (new_available == old_available) - return FALSE; - - state = nm_device_get_state (device); - if (state == NM_DEVICE_STATE_UNAVAILABLE) { - if (new_available == TRUE) { - nm_device_state_changed (device, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_NONE); - changed = TRUE; - } - } else if (state >= NM_DEVICE_STATE_DISCONNECTED) { - if (new_available == FALSE) { - nm_device_state_changed (device, - NM_DEVICE_STATE_UNAVAILABLE, - NM_DEVICE_STATE_REASON_NONE); - changed = TRUE; - } - } - - return changed; -} - -/* NMDeviceInterface interface */ - -static void -set_enabled (NMDevice *device, gboolean enabled) -{ - NMDeviceWimax *self = NM_DEVICE_WIMAX (device); - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - gboolean old_available; - int ret; - const char *iface; - - iface = nm_device_get_iface (NM_DEVICE (self)); - - nm_log_dbg (LOGD_WIMAX, "(%s): setting radio enabled %d -> %d", - iface, priv->enabled, enabled); - if (priv->enabled == enabled) - return; - - old_available = nm_device_is_available (NM_DEVICE (device), NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); - priv->enabled = enabled; - - nm_log_dbg (LOGD_WIMAX, "(%s): radio now %s", - iface, priv->enabled ? "enabled" : "disabled"); - - /* Set the WiMAX device RF state to the current user-specified enabled state */ - if (priv->sdk) { - ret = iwmx_sdk_rf_state_set (priv->sdk, - enabled ? WIMAX_API_RF_ON : WIMAX_API_RF_OFF); - if (ret < 0 && ret != -EINPROGRESS) { - nm_log_warn (LOGD_WIMAX, "(%s): failed to %s radio", - iface, priv->enabled ? "enable" : "disable"); - } - } - - update_availability (self, old_available); -} - -/* NMDevice methods */ - -static gboolean -check_connection_compatible (NMDevice *device, NMConnection *connection) -{ - NMSettingConnection *s_con; - NMSettingWimax *s_wimax; - const char *connection_type; - const char *mac; - - if (!NM_DEVICE_CLASS (nm_device_wimax_parent_class)->check_connection_compatible (device, connection)) - return FALSE; - - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - - connection_type = nm_setting_connection_get_connection_type (s_con); - if (strcmp (connection_type, NM_SETTING_WIMAX_SETTING_NAME)) - return FALSE; - - s_wimax = nm_connection_get_setting_wimax (connection); - if (!s_wimax) - return FALSE; - - mac = nm_setting_wimax_get_mac_address (s_wimax); - if (mac && !nm_utils_hwaddr_matches (mac, -1, nm_device_get_hw_address (device), -1)) - return FALSE; - - return TRUE; -} - -static gboolean -check_connection_available (NMDevice *device, - NMConnection *connection, - NMDeviceCheckConAvailableFlags flags, - const char *specific_object) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device); - const GSList *ns_iter = NULL; - NMWimaxNsp *nsp; - - /* a connection that is available for a certain @specific_object, MUST - * also be available in general (without @specific_object). */ - - if (specific_object) { - nsp = get_nsp_by_path (NM_DEVICE_WIMAX (device), specific_object); - return nsp ? nm_wimax_nsp_check_compatible (nsp, connection) : FALSE; - } - - /* Ensure the connection applies to an NSP in the scan list */ - for (ns_iter = priv->nsp_list; ns_iter; ns_iter = ns_iter->next) { - if (nm_wimax_nsp_check_compatible (NM_WIMAX_NSP (ns_iter->data), connection)) - return TRUE; - } - - return FALSE; -} - -static gboolean -complete_connection (NMDevice *device, - NMConnection *connection, - const char *specific_object, - const GSList *existing_connections, - GError **error) -{ - NMDeviceWimax *self = NM_DEVICE_WIMAX (device); - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - NMSettingWimax *s_wimax; - const char *setting_mac; - const char *hw_address; - const char *nsp_name = NULL; - NMWimaxNsp *nsp = NULL; - GSList *iter; - - s_wimax = nm_connection_get_setting_wimax (connection); - - if (!specific_object) { - /* If not given a specific object, we need at minimum an NSP name */ - if (!s_wimax) { - g_set_error_literal (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'wimax' setting is required if no NSP path was given."); - return FALSE; - } - - nsp_name = nm_setting_wimax_get_network_name (s_wimax); - if (!nsp_name || !strlen (nsp_name)) { - g_set_error_literal (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "A 'wimax' setting with a valid network name is required if no NSP path was given."); - return FALSE; - } - - /* Find a compatible NSP in the list */ - nsp = get_nsp_by_name (self, nsp_name); - - /* If we still don't have an NSP, then the WiMAX settings needs to be - * fully specified by the client. Might not be able to find the NSP - * if the scan didn't find the NSP yet. - */ - if (!nsp) { - if (!nm_setting_verify (NM_SETTING (s_wimax), NULL, error)) - return FALSE; - } - } else { - /* Find a compatible NSP in the list */ - for (iter = priv->nsp_list; iter; iter = g_slist_next (iter)) { - if (!strcmp (specific_object, nm_wimax_nsp_get_dbus_path (NM_WIMAX_NSP (iter->data)))) { - nsp = NM_WIMAX_NSP (iter->data); - break; - } - } - - if (!nsp) { - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_SPECIFIC_OBJECT_NOT_FOUND, - "The NSP %s was not in the scan list.", - specific_object); - return FALSE; - } - - nsp_name = nm_wimax_nsp_get_name (nsp); - } - - /* Add a WiMAX setting if one doesn't exist */ - if (!s_wimax) { - s_wimax = (NMSettingWimax *) nm_setting_wimax_new (); - nm_connection_add_setting (connection, NM_SETTING (s_wimax)); - } - - g_assert (nsp_name); - nm_utils_complete_generic (connection, - NM_SETTING_WIMAX_SETTING_NAME, - existing_connections, - nsp_name, - nsp_name, - NULL, - TRUE); - g_object_set (G_OBJECT (s_wimax), NM_SETTING_WIMAX_NETWORK_NAME, nsp_name, NULL); - - setting_mac = nm_setting_wimax_get_mac_address (s_wimax); - hw_address = nm_device_get_hw_address (device); - if (setting_mac) { - /* Make sure the setting MAC (if any) matches the device's permanent MAC */ - if (!nm_utils_hwaddr_matches (setting_mac, -1, hw_address, -1)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("connection does not match device")); - g_prefix_error (error, "%s.%s: ", NM_SETTING_WIMAX_SETTING_NAME, NM_SETTING_WIMAX_MAC_ADDRESS); - return FALSE; - } - } else { - /* Lock the connection to this device by default */ - if (!nm_utils_hwaddr_matches (hw_address, -1, NULL, ETH_ALEN)) - g_object_set (G_OBJECT (s_wimax), NM_SETTING_WIMAX_MAC_ADDRESS, hw_address, NULL); - } - - return TRUE; -} - -static gboolean -can_auto_connect (NMDevice *device, - NMConnection *connection, - char **specific_object) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device); - GSList *iter; - - if (!NM_DEVICE_CLASS (nm_device_wimax_parent_class)->can_auto_connect (device, connection, specific_object)) - return FALSE; - - for (iter = priv->nsp_list; iter; iter = iter->next) { - NMWimaxNsp *nsp = NM_WIMAX_NSP (iter->data); - - if (nm_wimax_nsp_check_compatible (nsp, connection)) { - *specific_object = (char *) nm_wimax_nsp_get_dbus_path (nsp); - return TRUE; - } - } - - return FALSE; -} - -static gboolean -is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device); - - if (!priv->enabled) - return FALSE; - - if (!priv->wimaxd_enabled) - return FALSE; - - if (!nm_wimax_util_sdk_is_initialized ()) - return FALSE; - - if (!priv->sdk) - return FALSE; - - return iwmxsdk_status_get (priv->sdk) >= WIMAX_API_DEVICE_STATUS_Ready; -} - -static void -clear_activation_timeout (NMDeviceWimax *self) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - - if (priv->activation_timeout_id) { - g_source_remove (priv->activation_timeout_id); - priv->activation_timeout_id = 0; - } - - priv->connect_failed = FALSE; -} - -static void -clear_link_timeout (NMDeviceWimax *self) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - - if (priv->link_timeout_id) { - g_source_remove (priv->link_timeout_id); - priv->link_timeout_id = 0; - } -} - -static void -clear_connected_poll (NMDeviceWimax *self) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - - if (priv->poll_id) { - g_source_remove (priv->poll_id); - priv->poll_id = 0; - } -} - -static NMActStageReturn -act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device); - NMActRequest *req; - GSList *iter; - const char *path; - NMWimaxNsp *nsp = NULL; - - clear_link_timeout (NM_DEVICE_WIMAX (device)); - - *reason = NM_DEVICE_STATE_REASON_NONE; - - req = nm_device_get_act_request (device); - if (!req) - return NM_ACT_STAGE_RETURN_FAILURE; - - path = nm_active_connection_get_specific_object (NM_ACTIVE_CONNECTION (req)); - if (!path) - return NM_ACT_STAGE_RETURN_FAILURE; - - /* Find the NSP in the scan list */ - for (iter = priv->nsp_list; iter; iter = iter->next) { - NMWimaxNsp *candidate = NM_WIMAX_NSP (iter->data); - - if (!strcmp (path, nm_wimax_nsp_get_dbus_path (candidate))) { - nsp = candidate; - break; - } - } - - /* Couldn't find the NSP for some reason */ - if (nsp == NULL) - return NM_ACT_STAGE_RETURN_FAILURE; - - set_current_nsp (NM_DEVICE_WIMAX (device), nsp); - - priv->prepare_done = TRUE; - - /* If the device is scanning, it won't connect, so we have to wait until - * it's not scanning to proceed to stage 2. - */ - if (priv->status == WIMAX_API_DEVICE_STATUS_Scanning) - return NM_ACT_STAGE_RETURN_POSTPONE; - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static NMActStageReturn -act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (device); - NMConnection *connection; - NMSettingWimax *s_wimax; - const char *nsp_name, *iface; - int ret; - - iface = nm_device_get_iface (device); - g_assert (iface); - - connection = nm_device_get_connection (device); - g_assert (connection); - - s_wimax = nm_connection_get_setting_wimax (connection); - g_assert (s_wimax); - - nsp_name = nm_setting_wimax_get_network_name (s_wimax); - g_assert (nsp_name); - - nm_log_info (LOGD_WIMAX, "(%s): connecting to NSP '%s'", - iface, nsp_name); - - priv->connect_failed = FALSE; - ret = iwmx_sdk_connect (priv->sdk, nsp_name); - if (ret < 0 && ret != -EINPROGRESS) { - nm_log_err (LOGD_WIMAX, "(%s): failed to connect to NSP '%s'", - iface, nsp_name); - *reason = NM_DEVICE_STATE_REASON_CONFIG_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; - } - - /* FIXME: Is 40 seconds good estimation? I have no idea */ - priv->activation_timeout_id = g_timeout_add_seconds (40, activation_timed_out, device); - - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -static void -force_disconnect (NMDeviceWimax *self, struct wmxsdk *sdk) -{ - WIMAX_API_DEVICE_STATUS status; - int ret; - const char *iface; - - g_return_if_fail (sdk != NULL); - - iface = nm_device_get_iface (NM_DEVICE (self)); - - status = iwmxsdk_status_get (sdk); - if ((int) status < 0) { - nm_log_err (LOGD_WIMAX, "(%s): failed to read WiMAX device status: %d", - iface, status); - return; - } - - if ( status == WIMAX_API_DEVICE_STATUS_Connecting - || status == WIMAX_API_DEVICE_STATUS_Data_Connected) { - nm_log_dbg (LOGD_WIMAX, "(%s): requesting disconnect", iface); - ret = iwmx_sdk_disconnect (sdk); - if (ret < 0 && ret != -EINPROGRESS) { - nm_log_err (LOGD_WIMAX, "(%s): failed to disconnect WiMAX device: %d", - iface, ret); - } - } -} - -static void -deactivate (NMDevice *device) -{ - NMDeviceWimax *self = NM_DEVICE_WIMAX (device); - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - - clear_activation_timeout (self); - clear_link_timeout (self); - clear_connected_poll (self); - - set_current_nsp (self, NULL); - - if (priv->sdk) { - /* Read explicit status here just to make sure we have the most - * up-to-date status and to ensure we disconnect if needed. - */ - force_disconnect (self, priv->sdk); - } -} - -/*************************************************************************/ - -static void -wmx_state_change_cb (struct wmxsdk *wmxsdk, - WIMAX_API_DEVICE_STATUS new_status, - WIMAX_API_DEVICE_STATUS old_status, - WIMAX_API_STATUS_REASON reason, - WIMAX_API_CONNECTION_PROGRESS_INFO progress, - void *user_data) -{ - NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data); - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - NMDeviceState state; - const char *iface; - gboolean old_available = FALSE; - const char *nsp_name = NULL; - - iface = nm_device_get_iface (NM_DEVICE (self)); - nm_log_info (LOGD_WIMAX, "(%s): wimax state change %s -> %s (%s (%d))", - iface, - iwmx_sdk_dev_status_to_str (old_status), - iwmx_sdk_dev_status_to_str (new_status), - iwmx_sdk_con_progress_to_str (progress), - progress); - - if (new_status == old_status) - return; - - state = nm_device_get_state (NM_DEVICE (self)); - old_available = nm_device_is_available (NM_DEVICE (self), NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); - - priv->status = new_status; - if (priv->current_nsp) - nsp_name = nm_wimax_nsp_get_name (priv->current_nsp); - - switch (new_status) { - case WIMAX_API_DEVICE_STATUS_UnInitialized: - case WIMAX_API_DEVICE_STATUS_RF_OFF_HW_SW: - case WIMAX_API_DEVICE_STATUS_RF_OFF_HW: - case WIMAX_API_DEVICE_STATUS_RF_OFF_SW: - if (priv->wimaxd_enabled) { - priv->wimaxd_enabled = FALSE; - if (update_availability (self, old_available)) - return; - } - break; - case WIMAX_API_DEVICE_STATUS_Connecting: - case WIMAX_API_DEVICE_STATUS_Data_Connected: - /* If for some reason we're initially connected, force a disconnect here */ - if (state < NM_DEVICE_STATE_DISCONNECTED) - force_disconnect (self, wmxsdk); - /* Fall through */ - case WIMAX_API_DEVICE_STATUS_Ready: - case WIMAX_API_DEVICE_STATUS_Scanning: - if (priv->wimaxd_enabled == FALSE) { - priv->wimaxd_enabled = TRUE; - if (update_availability (self, old_available)) - return; - } - break; - default: - nm_log_warn (LOGD_WIMAX, "(%s): unhandled WiMAX device state %d", - iface, new_status); - break; - } - - /* Handle activation success and failure */ - if (nm_device_is_activating (NM_DEVICE (self))) { - if (new_status == WIMAX_API_DEVICE_STATUS_Data_Connected) { - /* Success */ - clear_activation_timeout (self); - - nm_log_info (LOGD_WIMAX, "(%s): connected to '%s'", - iface, nsp_name); - nm_device_activate_schedule_stage3_ip_config_start (NM_DEVICE (self)); - return; - } - - if (priv->connect_failed) { - /* Connection attempt failed */ - nm_log_info (LOGD_WIMAX, "(%s): connection to '%s' failed: (%d) %s", - iface, nsp_name, reason, iwmx_sdk_reason_to_str (reason)); - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return; - } - - /* If stage2 was postponed because the device was scanning or something, - * then check if we need to move to stage2 now that the device might be - * ready. - */ - if (state == NM_DEVICE_STATE_PREPARE && priv->prepare_done) { - if ( new_status == WIMAX_API_DEVICE_STATUS_Ready - || new_status == WIMAX_API_DEVICE_STATUS_Connecting) { - nm_device_activate_schedule_stage2_device_config (NM_DEVICE (self)); - return; - } - } - } - - /* Handle disconnection */ - if (state == NM_DEVICE_STATE_ACTIVATED) { - if ( old_status == WIMAX_API_DEVICE_STATUS_Data_Connected - && new_status < WIMAX_API_DEVICE_STATUS_Connecting) { - - nm_log_info (LOGD_WIMAX, "(%s): disconnected from '%s': (%d) %s", - iface, nsp_name, reason, iwmx_sdk_reason_to_str (reason)); - - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_CONFIG_FAILED); - } - } -} - -static gboolean -link_timeout_cb (gpointer user_data) -{ - NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data); - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - - priv->link_timeout_id = 0; - - nm_log_dbg (LOGD_WIMAX, "(%s): link timed out", nm_device_get_iface (NM_DEVICE (self))); - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_CARRIER); - - return FALSE; -} - -static void -wmx_media_status_cb (struct wmxsdk *wmxsdk, - WIMAX_API_MEDIA_STATUS new_status, - void *user_data) -{ - NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data); - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - NMDeviceState state; - const char *iface; - - iface = nm_device_get_iface (NM_DEVICE (self)); - state = nm_device_get_state (NM_DEVICE (self)); - - nm_log_dbg (LOGD_WIMAX, "(%s): media status change to %s", - iface, iwmx_sdk_media_status_to_str (new_status)); - - /* We only care about media events while activated */ - if (state != NM_DEVICE_STATE_ACTIVATED) - return; - - clear_link_timeout (self); - - switch (new_status) { - case WIMAX_API_MEDIA_STATUS_LINK_UP: - break; - case WIMAX_API_MEDIA_STATUS_LINK_DOWN: - nm_log_dbg (LOGD_WIMAX, "(%s): starting link timeout", iface); - priv->link_timeout_id = g_timeout_add_seconds (15, link_timeout_cb, self); - break; - case WIMAX_API_MEDIA_STATUS_LINK_RENEW: - nm_log_dbg (LOGD_WIMAX, "(%s): renewing DHCP lease", iface); - if (!nm_device_dhcp4_renew (NM_DEVICE (self), TRUE)) { - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_DHCP_FAILED); - } - break; - default: - nm_log_err (LOGD_WIMAX, "(%s): unhandled media status %d", iface, new_status); - break; - } -} - -static void -wmx_connect_result_cb (struct wmxsdk *wmxsdk, - WIMAX_API_NETWORK_CONNECTION_RESP result, - void *user_data) -{ - NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data); - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - - if (nm_device_is_activating (NM_DEVICE (self))) { - priv->connect_failed = (result == WIMAX_API_CONNECTION_SUCCESS); - /* Wait for the state change so we can get the reason code; we - * cache the connect failure so we don't have to wait for the - * activation timeout. - */ - } -} - -static void -remove_outdated_nsps (NMDeviceWimax *self, - WIMAX_API_NSP_INFO_EX *nsp_list, - guint32 list_size) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - GSList *iter; - GSList *to_remove = NULL; - - for (iter = priv->nsp_list; iter; iter = iter->next) { - NMWimaxNsp *nsp = NM_WIMAX_NSP (iter->data); - gboolean found = FALSE; - int i; - - for (i = 0; i < list_size; i++) { - WIMAX_API_NSP_INFO_EX *info = &nsp_list[i]; - - if (!g_strcmp0 (nm_wimax_nsp_get_name (nsp), (char *) info->NSPName)) { - found = TRUE; - break; - } - } - - if (!found) - to_remove = g_slist_prepend (to_remove, nsp); - } - - for (iter = to_remove; iter; iter = iter->next) { - NMWimaxNsp *nsp = NM_WIMAX_NSP (iter->data); - - emit_nsp_added_removed (self, NSP_REMOVED, nsp, FALSE); - priv->nsp_list = g_slist_remove (priv->nsp_list, nsp); - g_object_unref (nsp); - } - - if (g_slist_length(to_remove) > 0) - nm_device_recheck_available_connections (NM_DEVICE (self)); - - g_slist_free (to_remove); -} - -static void -wmx_scan_result_cb (struct wmxsdk *wmxsdk, - WIMAX_API_NSP_INFO_EX *nsps, - guint num_nsps, - void *user_data) -{ - NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data); - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - const char *iface = nm_device_get_iface (NM_DEVICE (self)); - int i; - - remove_outdated_nsps (self, nsps, num_nsps); - - /* Add new NSPs and update existing ones */ - for (i = 0; i < num_nsps; i++) { - WIMAX_API_NSP_INFO_EX *sdk_nsp = &nsps[i]; - const char *nsp_name = (const char *) sdk_nsp->NSPName; - NMWimaxNspNetworkType net_type; - guint signalq; - NMWimaxNsp *nsp; - gboolean new_nsp; - - nsp = get_nsp_by_name (self, nsp_name); - new_nsp = (nsp == NULL); - if (new_nsp) { - nsp = nm_wimax_nsp_new (nsp_name); - nm_log_dbg (LOGD_WIMAX, "(%s): new WiMAX NSP '%s'", iface, nsp_name); - } - - net_type = nm_wimax_util_convert_network_type (sdk_nsp->networkType); - if (net_type != nm_wimax_nsp_get_network_type (nsp)) - g_object_set (nsp, NM_WIMAX_NSP_NETWORK_TYPE, net_type, NULL); - - signalq = CLAMP (sdk_nsp->linkQuality, 0, 100); - if (signalq != nm_wimax_nsp_get_signal_quality (nsp)) - g_object_set (nsp, NM_WIMAX_NSP_SIGNAL_QUALITY, signalq, NULL); - - nm_log_dbg (LOGD_WIMAX, "(%s): WiMAX NSP '%s' quality %d%% type %d", - iface, nsp_name, sdk_nsp->linkQuality, net_type); - - if (new_nsp) { - priv->nsp_list = g_slist_append (priv->nsp_list, nsp); - nm_wimax_nsp_export_to_dbus (nsp); - emit_nsp_added_removed (self, NSP_ADDED, nsp, TRUE); - } - } -} - -static void -wmx_removed_cb (struct wmxsdk *wmxsdk, void *user_data) -{ - NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data); - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - - if (!priv->sdk) { - nm_log_dbg (LOGD_WIMAX, "(%s): removed unhandled WiMAX interface", wmxsdk->ifname); - return; - } - - nm_log_dbg (LOGD_WIMAX, "(%s): removed WiMAX interface", wmxsdk->ifname); - - /* Clear callbacks just in case we don't hold the last reference */ - iwmx_sdk_set_callbacks (priv->sdk, NULL, NULL, NULL, NULL, NULL, NULL); - wmxsdk_unref (priv->sdk); - priv->sdk = NULL; - - priv->status = WIMAX_API_DEVICE_STATUS_UnInitialized; - nm_device_state_changed (NM_DEVICE (self), - NM_DEVICE_STATE_UNAVAILABLE, - NM_DEVICE_STATE_REASON_NONE); -} - -/*************************************************************************/ - -static inline gint -sdk_rssi_to_dbm (guint raw_rssi) -{ - /* Values range from 0x00 to 0x53, where -123dBm is encoded as 0x00 and - * -40dBm encoded as 0x53 in 1dB increments. - */ - return raw_rssi - 123; -} - -static inline gint -sdk_cinr_to_db (guint raw_cinr) -{ - /* Values range from 0x00 to 0x3F, where -10dB is encoded as 0x00 and - * 53dB encoded as 0x3F in 1dB increments. - */ - return raw_cinr - 10; -} - -static inline gint -sdk_tx_pow_to_dbm (guint raw_tx_pow) -{ - /* Values range from 0x00 to 0xFF, where -84dBm is encoded as 0x00 and - * 43.5dBm is encoded as 0xFF in 0.5dB increments. Normalize so that - * 0 dBm == 0. - */ - return (int) (((double) raw_tx_pow / 2.0) - 84) * 2; -} - -static void -set_link_status (NMDeviceWimax *self, WIMAX_API_LINK_STATUS_INFO_EX *link_status) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - guint center_freq = 0; - gint conv_rssi = 0, conv_cinr = 0, conv_tx_pow = 0; - char *new_bsid = NULL; - - if (link_status) { - center_freq = link_status->centerFrequency; - conv_rssi = sdk_rssi_to_dbm (link_status->RSSI); - conv_cinr = sdk_cinr_to_db (link_status->CINR); - conv_tx_pow = sdk_tx_pow_to_dbm (link_status->txPWR); - new_bsid = nm_utils_hwaddr_ntoa (link_status->bsId, 6); - } - - if (priv->center_freq != center_freq) { - priv->center_freq = center_freq; - g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_CENTER_FREQUENCY); - } - - if (priv->rssi != conv_rssi) { - priv->rssi = conv_rssi; - g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_RSSI); - } - - if (priv->cinr != conv_cinr) { - priv->cinr = conv_cinr; - g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_CINR); - } - - if (priv->tx_power != conv_tx_pow) { - priv->tx_power = conv_tx_pow; - g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_TX_POWER); - } - - if (g_strcmp0 (priv->bsid, new_bsid) != 0) { - g_free (priv->bsid); - priv->bsid = new_bsid; - g_object_notify (G_OBJECT (self), NM_DEVICE_WIMAX_BSID); - } else - g_free (new_bsid); -} - -static gboolean -connected_poll_cb (gpointer user_data) -{ - NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data); - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - WIMAX_API_CONNECTED_NSP_INFO_EX *sdk_nsp; - WIMAX_API_LINK_STATUS_INFO_EX *link_status; - - g_return_val_if_fail (priv->sdk != NULL, FALSE); - - /* Get details of the connected NSP */ - sdk_nsp = iwmx_sdk_get_connected_network (priv->sdk); - if (sdk_nsp) { - const char *nsp_name = (const char *) sdk_nsp->NSPName; - NMWimaxNsp *nsp; - - nsp = get_nsp_by_name (self, nsp_name); - if (nsp) { - NMWimaxNspNetworkType net_type; - guint signalq; - - net_type = nm_wimax_util_convert_network_type (sdk_nsp->networkType); - if (net_type != nm_wimax_nsp_get_network_type (nsp)) - g_object_set (nsp, NM_WIMAX_NSP_NETWORK_TYPE, net_type, NULL); - - signalq = sdk_nsp->linkQuality; - if (signalq != nm_wimax_nsp_get_signal_quality (nsp)) - g_object_set (nsp, NM_WIMAX_NSP_SIGNAL_QUALITY, signalq, NULL); - - nm_log_dbg (LOGD_WIMAX, "(%s): WiMAX NSP '%s' quality %d%% type %d", - nm_device_get_iface (NM_DEVICE (self)), - nsp_name, sdk_nsp->linkQuality, net_type); - } - free (sdk_nsp); - } - - /* Get details of the current radio link */ - link_status = iwmx_sdk_get_link_status_info (priv->sdk); - if (link_status) { - set_link_status (self, link_status); - free (link_status); - } - - return TRUE; /* reschedule */ -} - -static void -device_state_changed (NMDevice *device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - NMDeviceWimax *self = NM_DEVICE_WIMAX (device); - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - - /* Reset our stage1 (Prepare) done marker since it's only valid while in stage1 */ - priv->prepare_done = FALSE; - - if (new_state < NM_DEVICE_STATE_DISCONNECTED) - remove_all_nsps (self); - - /* Request initial NSP list when device is first started */ - if ( new_state == NM_DEVICE_STATE_DISCONNECTED - && old_state < NM_DEVICE_STATE_DISCONNECTED) { - if (priv->sdk) - iwmx_sdk_get_networks (priv->sdk); - } - - if (new_state == NM_DEVICE_STATE_FAILED || new_state <= NM_DEVICE_STATE_DISCONNECTED) { - set_current_nsp (self, NULL); - clear_activation_timeout (self); - } - - if (new_state == NM_DEVICE_STATE_ACTIVATED) { - /* poll link quality and BSID */ - clear_connected_poll (self); - priv->poll_id = g_timeout_add_seconds (10, connected_poll_cb, self); - connected_poll_cb (self); - } else { - clear_link_timeout (self); - clear_connected_poll (self); - set_link_status (self, NULL); - } -} - -/*************************************************************************/ - -static gboolean -sdk_action_defer_cb (gpointer user_data) -{ - NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data); - gboolean old_available = nm_device_is_available (NM_DEVICE (self), NM_DEVICE_CHECK_DEV_AVAILABLE_NONE); - - NM_DEVICE_WIMAX_GET_PRIVATE (self)->sdk_action_defer_id = 0; - update_availability (self, old_available); - return FALSE; -} - -static void -wmx_new_sdk_cb (struct wmxsdk *sdk, void *user_data) -{ - NMDeviceWimax *self = NM_DEVICE_WIMAX (user_data); - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - - /* We only track one wmxsdk at a time because the WiMAX SDK is pretty stupid */ - if (priv->sdk) { - nm_log_dbg (LOGD_WIMAX, "(%s): WiMAX interface already known", sdk->ifname); - return; - } - - nm_log_dbg (LOGD_WIMAX, "(%s): new WiMAX interface (%s)", sdk->ifname, sdk->name); - - /* Now that we have an SDK, schedule an idle handler to start the device up */ - priv->sdk = wmxsdk_ref (sdk); - iwmx_sdk_set_callbacks(priv->sdk, - wmx_state_change_cb, - wmx_media_status_cb, - wmx_connect_result_cb, - wmx_scan_result_cb, - wmx_removed_cb, - self); - iwmx_sdk_set_fast_reconnect_enabled (priv->sdk, 0); - - if (!priv->sdk_action_defer_id) - priv->sdk_action_defer_id = g_idle_add (sdk_action_defer_cb, self); -} - -/*************************************************************************/ - -NMDevice * -nm_device_wimax_new (NMPlatformLink *platform_device) -{ - NMDevice *device; - - g_return_val_if_fail (platform_device != NULL, NULL); - - device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_WIMAX, - NM_DEVICE_PLATFORM_DEVICE, platform_device, - NM_DEVICE_TYPE_DESC, "WiMAX", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_WIMAX, - NM_DEVICE_RFKILL_TYPE, RFKILL_TYPE_WIMAX, - NULL); - if (device) { - struct wmxsdk *sdk; - - nm_wimax_util_sdk_ref (); - - /* See if the SDK already knows about this interface */ - sdk = iwmx_sdk_get_wmxsdk_for_iface (platform_device->name); - if (sdk) - wmx_new_sdk_cb (sdk, device); - - /* If it doesn't, we want to be notified when it does */ - iwmx_sdk_new_callback_register (wmx_new_sdk_cb, device); - } - - return device; -} - -static void -nm_device_wimax_init (NMDeviceWimax *self) -{ - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - - priv->status = WIMAX_API_DEVICE_STATUS_UnInitialized; -} - -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMDeviceWimax *self = NM_DEVICE_WIMAX (object); - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - GPtrArray *array; - GSList *iter; - - switch (prop_id) { - case PROP_NSPS: - array = g_ptr_array_sized_new (4); - for (iter = priv->nsp_list; iter; iter = g_slist_next (iter)) - g_ptr_array_add (array, g_strdup (nm_wimax_nsp_get_dbus_path (NM_WIMAX_NSP (iter->data)))); - g_value_take_boxed (value, array); - break; - case PROP_ACTIVE_NSP: - if (priv->current_nsp) - g_value_set_boxed (value, nm_wimax_nsp_get_dbus_path (priv->current_nsp)); - else - g_value_set_boxed (value, "/"); - break; - case PROP_CENTER_FREQ: - g_value_set_uint (value, priv->center_freq); - break; - case PROP_RSSI: - g_value_set_int (value, priv->rssi); - break; - case PROP_CINR: - g_value_set_int (value, priv->cinr); - break; - case PROP_TX_POWER: - g_value_set_int (value, priv->tx_power); - break; - case PROP_BSID: - g_value_set_string (value, priv->bsid); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -dispose (GObject *object) -{ - NMDeviceWimax *self = NM_DEVICE_WIMAX (object); - NMDeviceWimaxPrivate *priv = NM_DEVICE_WIMAX_GET_PRIVATE (self); - - if (priv->disposed) - goto done; - - priv->disposed = TRUE; - - clear_activation_timeout (self); - clear_link_timeout (self); - clear_connected_poll (self); - - if (priv->sdk_action_defer_id) - g_source_remove (priv->sdk_action_defer_id); - - if (priv->sdk) { - iwmx_sdk_set_callbacks (priv->sdk, NULL, NULL, NULL, NULL, NULL, NULL); - wmxsdk_unref (priv->sdk); - } - - g_free (priv->bsid); - - set_current_nsp (self, NULL); - - g_slist_free_full (priv->nsp_list, g_object_unref); - - iwmx_sdk_new_callback_unregister (wmx_new_sdk_cb, self); - nm_wimax_util_sdk_unref (); - -done: - G_OBJECT_CLASS (nm_device_wimax_parent_class)->dispose (object); -} - -static void -nm_device_wimax_class_init (NMDeviceWimaxClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - - g_type_class_add_private (object_class, sizeof (NMDeviceWimaxPrivate)); - - /* Virtual methods */ - object_class->set_property = set_property; - object_class->get_property = get_property; - object_class->dispose = dispose; - - device_class->check_connection_compatible = check_connection_compatible; - device_class->check_connection_available = check_connection_available; - device_class->complete_connection = complete_connection; - device_class->can_auto_connect = can_auto_connect; - device_class->is_available = is_available; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->act_stage2_config = act_stage2_config; - device_class->deactivate = deactivate; - device_class->set_enabled = set_enabled; - - device_class->state_changed = device_state_changed; - - /* Properties */ - g_object_class_install_property - (object_class, PROP_NSPS, - g_param_spec_boxed (NM_DEVICE_WIMAX_NSPS, "", "", - DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_ACTIVE_NSP, - g_param_spec_boxed (NM_DEVICE_WIMAX_ACTIVE_NSP, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_CENTER_FREQ, - g_param_spec_uint (NM_DEVICE_WIMAX_CENTER_FREQUENCY, "", "", - 0, G_MAXUINT, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_RSSI, - g_param_spec_int (NM_DEVICE_WIMAX_RSSI, "", "", - G_MININT, G_MAXINT, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_CINR, - g_param_spec_int (NM_DEVICE_WIMAX_CINR, "", "", - G_MININT, G_MAXINT, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_TX_POWER, - g_param_spec_int (NM_DEVICE_WIMAX_TX_POWER, "", "", - G_MININT, G_MAXINT, 0, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_BSID, - g_param_spec_string (NM_DEVICE_WIMAX_BSID, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - /* Signals */ - signals[NSP_ADDED] = - g_signal_new ("nsp-added", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMDeviceWimaxClass, nsp_added), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - G_TYPE_OBJECT); - - signals[NSP_REMOVED] = - g_signal_new ("nsp-removed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMDeviceWimaxClass, nsp_removed), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - G_TYPE_OBJECT); - - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_device_wimax_object_info); -} diff --git a/src/devices/wimax/nm-device-wimax.h b/src/devices/wimax/nm-device-wimax.h deleted file mode 100644 index 30b2481f..00000000 --- a/src/devices/wimax/nm-device-wimax.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2010 - 2011 Red Hat, Inc. - * Copyright (C) 2009 Novell, Inc. - */ - -#ifndef __NETWORKMANAGER_DEVICE_WIMAX_H__ -#define __NETWORKMANAGER_DEVICE_WIMAX_H__ - -#include "nm-device.h" -#include "nm-wimax-nsp.h" - -G_BEGIN_DECLS - -#define NM_TYPE_DEVICE_WIMAX (nm_device_wimax_get_type ()) -#define NM_DEVICE_WIMAX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEVICE_WIMAX, NMDeviceWimax)) -#define NM_DEVICE_WIMAX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEVICE_WIMAX, NMDeviceWimaxClass)) -#define NM_IS_DEVICE_WIMAX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEVICE_WIMAX)) -#define NM_IS_DEVICE_WIMAX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEVICE_WIMAX)) -#define NM_DEVICE_WIMAX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEVICE_WIMAX, NMDeviceWimaxClass)) - -#define NM_DEVICE_WIMAX_NSPS "nsps" -#define NM_DEVICE_WIMAX_ACTIVE_NSP "active-nsp" -#define NM_DEVICE_WIMAX_CENTER_FREQUENCY "center-frequency" -#define NM_DEVICE_WIMAX_RSSI "rssi" -#define NM_DEVICE_WIMAX_CINR "cinr" -#define NM_DEVICE_WIMAX_TX_POWER "tx-power" -#define NM_DEVICE_WIMAX_BSID "bsid" - -typedef struct { - NMDevice parent; -} NMDeviceWimax; - -typedef struct { - NMDeviceClass parent; - - /* Signals */ - void (*nsp_added) (NMDeviceWimax *wimax, NMWimaxNsp *nsp); - void (*nsp_removed) (NMDeviceWimax *wimax, NMWimaxNsp *nsp); - void (*properties_changed) (NMDeviceWimax *wimax, GHashTable *properties); -} NMDeviceWimaxClass; - -GType nm_device_wimax_get_type (void); - -NMDevice *nm_device_wimax_new (NMPlatformLink *platform_device); - -G_END_DECLS - -#endif /* NM_DEVICE_WIMAX_H */ diff --git a/src/devices/wimax/nm-wimax-factory.c b/src/devices/wimax/nm-wimax-factory.c deleted file mode 100644 index 7dc580fc..00000000 --- a/src/devices/wimax/nm-wimax-factory.c +++ /dev/null @@ -1,91 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2011 - 2014 Red Hat, Inc. - */ - -#include "config.h" - -#include - -#include "nm-device-factory.h" -#include "nm-device-wimax.h" -#include "nm-platform.h" -#include "nm-setting-wimax.h" - -#define NM_TYPE_WIMAX_FACTORY (nm_wimax_factory_get_type ()) -#define NM_WIMAX_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_WIMAX_FACTORY, NMWimaxFactory)) - -typedef struct { - GObject parent; -} NMWimaxFactory; - -typedef struct { - GObjectClass parent; -} NMWimaxFactoryClass; - -static GType nm_wimax_factory_get_type (void); - -static void device_factory_interface_init (NMDeviceFactory *factory_iface); - -G_DEFINE_TYPE_EXTENDED (NMWimaxFactory, nm_wimax_factory, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_FACTORY, device_factory_interface_init)) - -/**************************************************************************/ - -G_MODULE_EXPORT NMDeviceFactory * -nm_device_factory_create (GError **error) -{ - return (NMDeviceFactory *) g_object_new (NM_TYPE_WIMAX_FACTORY, NULL); -} - -/**************************************************************************/ - -static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) -{ - /* FIXME: check udev 'DEVTYPE' instead; but since we only support Intel - * WiMAX devices for now this is appropriate. - */ - if (g_strcmp0 (plink->driver, "i2400m_usb") != 0) - return NULL; /* unsupported */ - - return (NMDevice *) nm_device_wimax_new (plink); -} - -NM_DEVICE_FACTORY_DECLARE_TYPES ( - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_WIMAX) - NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_WIMAX_SETTING_NAME) -) - -static void -device_factory_interface_init (NMDeviceFactory *factory_iface) -{ - factory_iface->new_link = new_link; - factory_iface->get_supported_types = get_supported_types; -} - -static void -nm_wimax_factory_init (NMWimaxFactory *factory) -{ -} - -static void -nm_wimax_factory_class_init (NMWimaxFactoryClass *wf_class) -{ -} - diff --git a/src/devices/wimax/nm-wimax-nsp.c b/src/devices/wimax/nm-wimax-nsp.c deleted file mode 100644 index f4db63f0..00000000 --- a/src/devices/wimax/nm-wimax-nsp.c +++ /dev/null @@ -1,241 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2010 - 2012 Red Hat, Inc. - * Copyright (C) 2009 Novell, Inc. - */ - -#include "config.h" - -#include "nm-wimax-nsp.h" -#include "nm-dbus-interface.h" -#include "nm-dbus-manager.h" -#include "nm-setting-wimax.h" -#include "nm-wimax-nsp-glue.h" -#include "nm-utils.h" - -G_DEFINE_TYPE (NMWimaxNsp, nm_wimax_nsp, G_TYPE_OBJECT) - -enum { - PROP_0, - - PROP_NAME, - PROP_SIGNAL_QUALITY, - PROP_NETWORK_TYPE, - - LAST_PROP -}; - -#define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_WIMAX_NSP, NMWimaxNspPrivate)) - -typedef struct { - char *dbus_path; - - char *name; - guint32 signal_quality; - NMWimaxNspNetworkType network_type; -} NMWimaxNspPrivate; - -NMWimaxNsp * -nm_wimax_nsp_new (const char *name) -{ - g_return_val_if_fail (name != NULL, NULL); - - return NM_WIMAX_NSP (g_object_new (NM_TYPE_WIMAX_NSP, - NM_WIMAX_NSP_NAME, name, - NULL)); -} - -const char * -nm_wimax_nsp_get_name (NMWimaxNsp *self) -{ - g_return_val_if_fail (NM_IS_WIMAX_NSP (self), NULL); - - return GET_PRIVATE (self)->name; -} - -guint32 -nm_wimax_nsp_get_signal_quality (NMWimaxNsp *self) -{ - g_return_val_if_fail (NM_IS_WIMAX_NSP (self), 0); - - return GET_PRIVATE (self)->signal_quality; -} - -NMWimaxNspNetworkType -nm_wimax_nsp_get_network_type (NMWimaxNsp *self) -{ - g_return_val_if_fail (NM_IS_WIMAX_NSP (self), 0); - - return GET_PRIVATE (self)->network_type; -} - -void -nm_wimax_nsp_export_to_dbus (NMWimaxNsp *self) -{ - NMWimaxNspPrivate *priv; - static guint32 counter = 0; - - g_return_if_fail (NM_IS_WIMAX_NSP (self)); - - priv = GET_PRIVATE (self); - - g_return_if_fail (priv->dbus_path == NULL); - - priv->dbus_path = g_strdup_printf (NM_DBUS_PATH_WIMAX_NSP "/%d", counter++); - nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->dbus_path, self); -} - -const char * -nm_wimax_nsp_get_dbus_path (NMWimaxNsp *self) -{ - g_return_val_if_fail (NM_IS_WIMAX_NSP (self), NULL); - - return GET_PRIVATE (self)->dbus_path; -} - -gboolean -nm_wimax_nsp_check_compatible (NMWimaxNsp *self, - NMConnection *connection) -{ - NMWimaxNspPrivate *priv; - NMSettingWimax *s_wimax; - - g_return_val_if_fail (NM_IS_WIMAX_NSP (self), FALSE); - g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); - - priv = GET_PRIVATE (self); - - s_wimax = nm_connection_get_setting_wimax (connection); - if (!s_wimax) - return FALSE; - - return g_strcmp0 (nm_wimax_nsp_get_name (self), nm_setting_wimax_get_network_name (s_wimax)) == 0; -} - -static void -nm_wimax_nsp_init (NMWimaxNsp *self) -{ -} - -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - NMWimaxNspPrivate *priv = GET_PRIVATE (object); - guint32 quality; - guint network_type; - - switch (prop_id) { - case PROP_NAME: - /* Construct only */ - priv->name = g_value_dup_string (value); - break; - case PROP_SIGNAL_QUALITY: - quality = g_value_get_uint (value); - if (quality != priv->signal_quality) { - priv->signal_quality = CLAMP (quality, 0, 100); - g_object_notify (object, NM_WIMAX_NSP_SIGNAL_QUALITY); - } - break; - case PROP_NETWORK_TYPE: - network_type = g_value_get_uint (value); - if (network_type != priv->network_type) { - priv->network_type = network_type; - g_object_notify (object, NM_WIMAX_NSP_NETWORK_TYPE); - } - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - NMWimaxNsp *self = NM_WIMAX_NSP (object); - - switch (prop_id) { - case PROP_NAME: - g_value_set_string (value, nm_wimax_nsp_get_name (self)); - break; - case PROP_SIGNAL_QUALITY: - g_value_set_uint (value, nm_wimax_nsp_get_signal_quality (self)); - break; - case PROP_NETWORK_TYPE: - g_value_set_uint (value, nm_wimax_nsp_get_network_type (self)); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -finalize (GObject *object) -{ - NMWimaxNspPrivate *priv = GET_PRIVATE (object); - - g_free (priv->name); - g_free (priv->dbus_path); - - G_OBJECT_CLASS (nm_wimax_nsp_parent_class)->finalize (object); -} - -static void -nm_wimax_nsp_class_init (NMWimaxNspClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (object_class, sizeof (NMWimaxNspPrivate)); - - /* Virtual methods */ - object_class->set_property = set_property; - object_class->get_property = get_property; - object_class->finalize = finalize; - - g_object_class_install_property - (object_class, PROP_NAME, - g_param_spec_string (NM_WIMAX_NSP_NAME, "", "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_SIGNAL_QUALITY, - g_param_spec_uint (NM_WIMAX_NSP_SIGNAL_QUALITY, "", "", - 0, - 100, - 0, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - g_object_class_install_property - (object_class, PROP_NETWORK_TYPE, - g_param_spec_uint (NM_WIMAX_NSP_NETWORK_TYPE, "", "", - NM_WIMAX_NSP_NETWORK_TYPE_UNKNOWN, - NM_WIMAX_NSP_NETWORK_TYPE_ROAMING_PARTNER, - NM_WIMAX_NSP_NETWORK_TYPE_UNKNOWN, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (klass), - &dbus_glib_nm_wimax_nsp_object_info); -} diff --git a/src/devices/wimax/nm-wimax-nsp.h b/src/devices/wimax/nm-wimax-nsp.h deleted file mode 100644 index 8d0a6a14..00000000 --- a/src/devices/wimax/nm-wimax-nsp.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2009 Novell, Inc. - */ - -#ifndef __NETWORKMANAGER_WIMAX_NSP_H__ -#define __NETWORKMANAGER_WIMAX_NSP_H__ - -#include -#include "nm-wimax-types.h" -#include "nm-connection.h" - -#define NM_TYPE_WIMAX_NSP (nm_wimax_nsp_get_type ()) -#define NM_WIMAX_NSP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WIMAX_NSP, NMWimaxNsp)) -#define NM_WIMAX_NSP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_WIMAX_NSP, NMWimaxNspClass)) -#define NM_IS_WIMAX_NSP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_WIMAX_NSP)) -#define NM_IS_WIMAX_NSP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_WIMAX_NSP)) -#define NM_WIMAX_NSP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_WIMAX_NSP, NMWimaxNspClass)) - -#define NM_WIMAX_NSP_NAME "name" -#define NM_WIMAX_NSP_SIGNAL_QUALITY "signal-quality" -#define NM_WIMAX_NSP_NETWORK_TYPE "network-type" - -typedef struct { - GObject parent; -} NMWimaxNsp; - -typedef struct { - GObjectClass parent; - - /* Signals */ - void (*properties_changed) (NMWimaxNsp *nsp, GHashTable *properties); -} NMWimaxNspClass; - -GType nm_wimax_nsp_get_type (void); - -NMWimaxNsp *nm_wimax_nsp_new (const char *name); -const char *nm_wimax_nsp_get_name (NMWimaxNsp *self); -guint32 nm_wimax_nsp_get_signal_quality (NMWimaxNsp *self); -NMWimaxNspNetworkType nm_wimax_nsp_get_network_type (NMWimaxNsp *self); - -void nm_wimax_nsp_export_to_dbus (NMWimaxNsp *self); -const char *nm_wimax_nsp_get_dbus_path (NMWimaxNsp *self); - -gboolean nm_wimax_nsp_check_compatible (NMWimaxNsp *self, - NMConnection *connection); - -#endif /* NM_WIMAX_NSP_H */ diff --git a/src/devices/wimax/nm-wimax-types.h b/src/devices/wimax/nm-wimax-types.h deleted file mode 100644 index 207d2477..00000000 --- a/src/devices/wimax/nm-wimax-types.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2009 Novell, Inc. - */ - -#ifndef __NETWORKMANAGER_WIMAX_TYPES_H__ -#define __NETWORKMANAGER_WIMAX_TYPES_H__ - -typedef enum { - NM_WIMAX_NSP_NETWORK_TYPE_UNKNOWN, - NM_WIMAX_NSP_NETWORK_TYPE_HOME, - NM_WIMAX_NSP_NETWORK_TYPE_PARTNER, - NM_WIMAX_NSP_NETWORK_TYPE_ROAMING_PARTNER -} NMWimaxNspNetworkType; - -#endif /* NM_WIMAX_TYPES_H */ diff --git a/src/devices/wimax/nm-wimax-util.c b/src/devices/wimax/nm-wimax-util.c deleted file mode 100644 index 0ae285ae..00000000 --- a/src/devices/wimax/nm-wimax-util.c +++ /dev/null @@ -1,83 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2009 Novell, Inc. - */ - -#include "config.h" - -#include "nm-wimax-util.h" -#include "nm-utils.h" -#include "iwmxsdk.h" -#include "nm-logging.h" - -static guint sdk_refcount = 0; - -void -nm_wimax_util_sdk_ref (void) -{ - int ret = 0; - - if (sdk_refcount == 0) { - ret = iwmx_sdk_api_init (); - if (ret != 0) { - nm_log_warn (LOGD_WIMAX, "Failed to initialize WiMAX: %d", ret); - return; - } - } - sdk_refcount++; -} - -gboolean -nm_wimax_util_sdk_is_initialized (void) -{ - return sdk_refcount > 0; -} - -void -nm_wimax_util_sdk_unref (void) -{ - g_return_if_fail (sdk_refcount > 0); - - sdk_refcount--; - if (sdk_refcount == 0) - iwmx_sdk_api_exit (); -} - -NMWimaxNspNetworkType -nm_wimax_util_convert_network_type (WIMAX_API_NETWORK_TYPE wimax_network_type) -{ - NMWimaxNspNetworkType type; - - switch (wimax_network_type) { - case WIMAX_API_HOME: - type = NM_WIMAX_NSP_NETWORK_TYPE_HOME; - break; - case WIMAX_API_PARTNER: - type = NM_WIMAX_NSP_NETWORK_TYPE_PARTNER; - break; - case WIMAX_API_ROAMING_PARTNER: - type = NM_WIMAX_NSP_NETWORK_TYPE_ROAMING_PARTNER; - break; - default: - type = NM_WIMAX_NSP_NETWORK_TYPE_UNKNOWN; - break; - } - - return type; -} - diff --git a/src/devices/wimax/nm-wimax-util.h b/src/devices/wimax/nm-wimax-util.h deleted file mode 100644 index 5fedc6e8..00000000 --- a/src/devices/wimax/nm-wimax-util.h +++ /dev/null @@ -1,43 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2009 Novell, Inc. - */ - -#ifndef __NETWORKMANAGER_WIMAX_UTIL_H__ -#define __NETWORKMANAGER_WIMAX_UTIL_H__ - -#include - -#include "nm-macros-internal.h" - -NM_PRAGMA_WARNING_DISABLE("-Wstrict-prototypes") -#include -NM_PRAGMA_WARNING_REENABLE - -#include -#include "nm-wimax-types.h" - -void nm_wimax_util_sdk_ref (void); - -gboolean nm_wimax_util_sdk_is_initialized (void); - -void nm_wimax_util_sdk_unref (void); - -NMWimaxNspNetworkType nm_wimax_util_convert_network_type (WIMAX_API_NETWORK_TYPE wimax_network_type); - -#endif /* NM_WIMAX_UTIL_H */ diff --git a/src/devices/wwan/Makefile.am b/src/devices/wwan/Makefile.am index 055b07b9..107f630b 100644 --- a/src/devices/wwan/Makefile.am +++ b/src/devices/wwan/Makefile.am @@ -8,14 +8,14 @@ AM_CPPFLAGS = \ -I${top_srcdir}/src/devices \ -I${top_srcdir}/src/settings \ -I${top_srcdir}/src/platform \ - -I${top_srcdir}/include \ - -I$(top_builddir)/include \ + -I${top_builddir}/introspection \ + -I${top_srcdir}/shared \ + -I$(top_builddir)/shared \ -I${top_srcdir}/libnm-core \ -I${top_builddir}/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-wwan"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(DBUS_CFLAGS) \ $(GLIB_CFLAGS) \ $(MM_GLIB_CFLAGS) @@ -47,31 +47,29 @@ WWAN_SYMBOL_VIS_FILE=$(srcdir)/wwan-exports.ver libnm_wwan_la_LDFLAGS = \ -avoid-version \ -Wl,--version-script=$(WWAN_SYMBOL_VIS_FILE) -libnm_wwan_la_LIBADD = $(DBUS_LIBS) $(MM_GLIB_LIBS) +libnm_wwan_la_LIBADD = \ + $(top_builddir)/introspection/libnmdbus.la \ + $(GLIB_LIBS) \ + $(MM_GLIB_LIBS) ########################################################### -nm-device-modem-glue.h: $(top_srcdir)/introspection/nm-device-modem.xml - dbus-binding-tool --prefix=nm_device_modem --mode=glib-server --output=$@ $< - -BUILT_SOURCES += nm-device-modem-glue.h - SYMBOL_VIS_FILE=$(srcdir)/exports.ver libnm_device_plugin_wwan_la_SOURCES = \ nm-wwan-factory.c \ nm-wwan-factory.h \ nm-device-modem.c \ - nm-device-modem.h \ - nm-device-modem-glue.h + nm-device-modem.h libnm_device_plugin_wwan_la_LDFLAGS = \ -module -avoid-version \ -Wl,--version-script=$(SYMBOL_VIS_FILE) libnm_device_plugin_wwan_la_LIBADD = \ + $(top_builddir)/introspection/libnmdbus.la \ libnm-wwan.la \ - $(DBUS_LIBS) + $(GLIB_LIBS) ########################################################### diff --git a/src/devices/wwan/Makefile.in b/src/devices/wwan/Makefile.in index 571b1b7d..ac13135e 100644 --- a/src/devices/wwan/Makefile.in +++ b/src/devices/wwan/Makefile.in @@ -140,7 +140,8 @@ am__uninstall_files_from_dir = { \ am__installdirs = "$(DESTDIR)$(pkglibdir)" LTLIBRARIES = $(pkglib_LTLIBRARIES) am__DEPENDENCIES_1 = -libnm_device_plugin_wwan_la_DEPENDENCIES = libnm-wwan.la \ +libnm_device_plugin_wwan_la_DEPENDENCIES = \ + $(top_builddir)/introspection/libnmdbus.la libnm-wwan.la \ $(am__DEPENDENCIES_1) am_libnm_device_plugin_wwan_la_OBJECTS = nm-wwan-factory.lo \ nm-device-modem.lo @@ -154,8 +155,9 @@ libnm_device_plugin_wwan_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libnm_device_plugin_wwan_la_LDFLAGS) \ $(LDFLAGS) -o $@ -libnm_wwan_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) +libnm_wwan_la_DEPENDENCIES = \ + $(top_builddir)/introspection/libnmdbus.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) am__objects_1 = nm-modem-enum-types.lo am_libnm_wwan_la_OBJECTS = nm-modem-broadband.lo nm-modem-manager.lo \ nm-modem.lo $(am__objects_1) @@ -243,7 +245,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -255,8 +256,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -266,6 +265,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -320,16 +320,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -366,6 +363,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -394,7 +393,6 @@ 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@ @@ -409,6 +407,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -469,6 +469,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -476,6 +477,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -497,18 +499,18 @@ AM_CPPFLAGS = \ -I${top_srcdir}/src/devices \ -I${top_srcdir}/src/settings \ -I${top_srcdir}/src/platform \ - -I${top_srcdir}/include \ - -I$(top_builddir)/include \ + -I${top_builddir}/introspection \ + -I${top_srcdir}/shared \ + -I$(top_builddir)/shared \ -I${top_srcdir}/libnm-core \ -I${top_builddir}/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-wwan"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(DBUS_CFLAGS) \ $(GLIB_CFLAGS) \ $(MM_GLIB_CFLAGS) -BUILT_SOURCES = $(null) $(GLIB_GENERATED) nm-device-modem-glue.h +BUILT_SOURCES = $(null) $(GLIB_GENERATED) pkglib_LTLIBRARIES = libnm-wwan.la libnm-device-plugin-wwan.la ########################################################### @@ -531,22 +533,28 @@ libnm_wwan_la_LDFLAGS = \ -avoid-version \ -Wl,--version-script=$(WWAN_SYMBOL_VIS_FILE) -libnm_wwan_la_LIBADD = $(DBUS_LIBS) $(MM_GLIB_LIBS) +libnm_wwan_la_LIBADD = \ + $(top_builddir)/introspection/libnmdbus.la \ + $(GLIB_LIBS) \ + $(MM_GLIB_LIBS) + + +########################################################### SYMBOL_VIS_FILE = $(srcdir)/exports.ver libnm_device_plugin_wwan_la_SOURCES = \ nm-wwan-factory.c \ nm-wwan-factory.h \ nm-device-modem.c \ - nm-device-modem.h \ - nm-device-modem-glue.h + nm-device-modem.h libnm_device_plugin_wwan_la_LDFLAGS = \ -module -avoid-version \ -Wl,--version-script=$(SYMBOL_VIS_FILE) libnm_device_plugin_wwan_la_LIBADD = \ + $(top_builddir)/introspection/libnmdbus.la \ libnm-wwan.la \ - $(DBUS_LIBS) + $(GLIB_LIBS) ########################################################### @@ -887,11 +895,6 @@ include $(GLIB_MAKEFILE) @GNOME_CODE_COVERAGE_RULES@ -########################################################### - -nm-device-modem-glue.h: $(top_srcdir)/introspection/nm-device-modem.xml - dbus-binding-tool --prefix=nm_device_modem --mode=glib-server --output=$@ $< - @ENABLE_TESTS_TRUE@check-local: @ENABLE_TESTS_TRUE@ $(top_srcdir)/tools/check-exports.sh $(builddir)/.libs/libnm-device-plugin-wwan.so $(SYMBOL_VIS_FILE) @ENABLE_TESTS_TRUE@ $(top_srcdir)/tools/check-exports.sh $(builddir)/.libs/libnm-wwan.so $(WWAN_SYMBOL_VIS_FILE) diff --git a/src/devices/wwan/nm-device-modem-glue.h b/src/devices/wwan/nm-device-modem-glue.h deleted file mode 100644 index 21271491..00000000 --- a/src/devices/wwan/nm-device-modem-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_modem_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_modem_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_modem_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_modem_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_modem_object_info = { 1, - dbus_glib_nm_device_modem_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.Modem\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.Modem\0ModemCapabilities\0modem_capabilities\0read\0org.freedesktop.NetworkManager.Device.Modem\0CurrentCapabilities\0current_capabilities\0read\0\0" -}; - diff --git a/src/devices/wwan/nm-device-modem.c b/src/devices/wwan/nm-device-modem.c index ca724c04..edecd24d 100644 --- a/src/devices/wwan/nm-device-modem.c +++ b/src/devices/wwan/nm-device-modem.c @@ -21,14 +21,12 @@ #include "config.h" #include -#include +#include "nm-default.h" #include "nm-device-modem.h" #include "nm-modem.h" #include "nm-device-private.h" #include "nm-rfkill-manager.h" -#include "nm-logging.h" -#include "nm-dbus-manager.h" #include "nm-settings-connection.h" #include "nm-modem-broadband.h" #include "NetworkManagerUtils.h" @@ -37,12 +35,12 @@ #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceModem); +#include "nmdbus-device-modem.h" + G_DEFINE_TYPE (NMDeviceModem, nm_device_modem, NM_TYPE_DEVICE) #define NM_DEVICE_MODEM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_MODEM, NMDeviceModemPrivate)) -#include "nm-device-modem-glue.h" - typedef struct { NMModem *modem; NMDeviceModemCapabilities caps; @@ -108,7 +106,7 @@ modem_prepare_result (NMModem *modem, * the device to be auto-activated anymore, which would risk locking * the SIM if the incorrect PIN continues to be used. */ - g_object_set (G_OBJECT (device), NM_DEVICE_AUTOCONNECT, FALSE, NULL); + nm_device_set_autoconnect (device, FALSE); _LOGI (LOGD_MB, "disabling autoconnect due to failed SIM PIN"); } @@ -255,6 +253,12 @@ data_port_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) nm_device_ipv6_sysctl_set (self, "disable_ipv6", "1"); } +static void +ids_changed_cb (NMModem *modem, GParamSpec *pspec, gpointer user_data) +{ + nm_device_recheck_available_connections (NM_DEVICE (user_data)); +} + static void modem_state_cb (NMModem *modem, NMModemState new_state, @@ -332,7 +336,7 @@ device_state_changed (NMDevice *device, { NMDeviceModem *self = NM_DEVICE_MODEM (device); NMDeviceModemPrivate *priv = NM_DEVICE_MODEM_GET_PRIVATE (device); - NMConnection *connection = nm_device_get_connection (device); + NMConnection *connection = nm_device_get_applied_connection (device); g_assert (priv->modem); @@ -411,10 +415,7 @@ check_connection_available (NMDevice *device, return FALSE; if (state == NM_MODEM_STATE_LOCKED) { - NMSettingGsm *s_gsm = nm_connection_get_setting_gsm (connection); - - /* Can't use a connection without a PIN if the modem is locked */ - if (!s_gsm || !nm_setting_gsm_get_pin (s_gsm)) + if (!nm_connection_get_setting_gsm (connection)) return FALSE; } @@ -679,6 +680,10 @@ set_modem (NMDeviceModem *self, NMModem *modem) * while in the new ModemManager the data port is set afterwards when the bearer gets * created */ g_signal_connect (modem, "notify::" NM_MODEM_DATA_PORT, G_CALLBACK (data_port_changed_cb), self); + + g_signal_connect (modem, "notify::" NM_MODEM_DEVICE_ID, G_CALLBACK (ids_changed_cb), self); + g_signal_connect (modem, "notify::" NM_MODEM_SIM_ID, G_CALLBACK (ids_changed_cb), self); + g_signal_connect (modem, "notify::" NM_MODEM_SIM_OPERATOR_ID, G_CALLBACK (ids_changed_cb), self); } static void @@ -795,7 +800,7 @@ nm_device_modem_class_init (NMDeviceModemClass *mclass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (mclass), - &dbus_glib_nm_device_modem_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (mclass), + NMDBUS_TYPE_DEVICE_MODEM_SKELETON, + NULL); } diff --git a/src/devices/wwan/nm-device-modem.h b/src/devices/wwan/nm-device-modem.h index 996195c4..1cf399e1 100644 --- a/src/devices/wwan/nm-device-modem.h +++ b/src/devices/wwan/nm-device-modem.h @@ -21,9 +21,6 @@ #ifndef __NETWORKMANAGER_DEVICE_MODEM_H__ #define __NETWORKMANAGER_DEVICE_MODEM_H__ -#include -#include - #include "nm-device.h" #include "nm-modem.h" diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c index ec4f4a2f..427f3ed6 100644 --- a/src/devices/wwan/nm-modem-broadband.c +++ b/src/devices/wwan/nm-modem-broadband.c @@ -20,28 +20,51 @@ #include "config.h" -#include #include #include #include #include "nm-modem-broadband.h" #include "nm-core-internal.h" -#include "nm-logging.h" +#include "nm-default.h" #include "NetworkManagerUtils.h" #include "nm-device-private.h" #include "nm-platform.h" G_DEFINE_TYPE (NMModemBroadband, nm_modem_broadband, NM_TYPE_MODEM) +typedef enum { + CONNECT_STEP_FIRST, + CONNECT_STEP_WAIT_FOR_SIM, + CONNECT_STEP_UNLOCK, + CONNECT_STEP_WAIT_FOR_READY, + CONNECT_STEP_CONNECT, + CONNECT_STEP_LAST +} ConnectStep; + +typedef struct { + NMModemBroadband *self; + ConnectStep step; + + MMModemCapability caps; + NMConnection *connection; + GCancellable *cancellable; + MMSimpleConnectProperties *connect_properties; + GArray *ip_types; + guint ip_types_i; + GError *first_error; +} ConnectContext; + struct _NMModemBroadbandPrivate { /* The modem object from dbus */ MMObject *modem_object; /* Per-interface objects */ MMModem *modem_iface; MMModemSimple *simple_iface; + MMSim *sim_iface; /* Connection setup */ + ConnectContext *ctx; MMBearer *bearer; MMBearerIpConfig *ipv4_config; @@ -257,45 +280,45 @@ create_gsm_connect_properties (NMConnection *connection) return properties; } -typedef struct { - NMModemBroadband *self; - MMModemCapability caps; - MMSimpleConnectProperties *connect_properties; - GArray *ip_types; - guint ip_types_i; - GError *first_error; -} ActStageContext; - static void -act_stage_context_free (ActStageContext *ctx) +connect_context_clear (NMModemBroadband *self) { - g_clear_error (&ctx->first_error); - g_clear_pointer (&ctx->ip_types, (GDestroyNotify) g_array_unref); - g_clear_object (&ctx->connect_properties); - g_object_unref (ctx->self); - g_slice_free (ActStageContext, ctx); + if (self->priv->ctx) { + ConnectContext *ctx = self->priv->ctx; + + g_clear_error (&ctx->first_error); + g_clear_pointer (&ctx->ip_types, (GDestroyNotify) g_array_unref); + g_clear_object (&ctx->cancellable); + g_clear_object (&ctx->connection); + g_clear_object (&ctx->connect_properties); + g_clear_object (&ctx->self); + g_slice_free (ConnectContext, ctx); + self->priv->ctx = NULL; + } } -static void act_stage_context_step (ActStageContext *ctx); +static void connect_context_step (NMModemBroadband *self); static void connect_ready (MMModemSimple *simple_iface, GAsyncResult *res, - ActStageContext *ctx) + NMModemBroadband *self) { + ConnectContext *ctx = self->priv->ctx; GError *error = NULL; NMModemIPMethod ip4_method = NM_MODEM_IP_METHOD_UNKNOWN; NMModemIPMethod ip6_method = NM_MODEM_IP_METHOD_UNKNOWN; - ctx->self->priv->bearer = mm_modem_simple_connect_finish (simple_iface, res, &error); - if (!ctx->self->priv->bearer) { + self->priv->bearer = mm_modem_simple_connect_finish (simple_iface, res, &error); + if (!self->priv->bearer) { if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) || (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNAUTHORIZED) && - mm_modem_get_unlock_required (ctx->self->priv->modem_iface) == MM_MODEM_LOCK_SIM_PIN)) { - /* Request PIN */ - ask_for_pin (ctx->self); + mm_modem_get_unlock_required (self->priv->modem_iface) == MM_MODEM_LOCK_SIM_PIN)) { g_error_free (error); - act_stage_context_free (ctx); + + /* Request PIN */ + ask_for_pin (self); + connect_context_clear (self); return; } @@ -312,79 +335,190 @@ connect_ready (MMModemSimple *simple_iface, * retry with the next one, if any. */ ctx->ip_types_i++; - act_stage_context_step (ctx); + connect_context_clear (self); return; } /* Grab IP configurations */ - ctx->self->priv->ipv4_config = mm_bearer_get_ipv4_config (ctx->self->priv->bearer); - if (ctx->self->priv->ipv4_config) - ip4_method = get_bearer_ip_method (ctx->self->priv->ipv4_config); + self->priv->ipv4_config = mm_bearer_get_ipv4_config (self->priv->bearer); + if (self->priv->ipv4_config) + ip4_method = get_bearer_ip_method (self->priv->ipv4_config); - ctx->self->priv->ipv6_config = mm_bearer_get_ipv6_config (ctx->self->priv->bearer); - if (ctx->self->priv->ipv6_config) - ip6_method = get_bearer_ip_method (ctx->self->priv->ipv6_config); + self->priv->ipv6_config = mm_bearer_get_ipv6_config (self->priv->bearer); + if (self->priv->ipv6_config) + ip6_method = get_bearer_ip_method (self->priv->ipv6_config); if (ip4_method == NM_MODEM_IP_METHOD_UNKNOWN && ip6_method == NM_MODEM_IP_METHOD_UNKNOWN) { nm_log_warn (LOGD_MB, "(%s): failed to connect modem: invalid bearer IP configuration", - nm_modem_get_uid (NM_MODEM (ctx->self))); - g_signal_emit_by_name (ctx->self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - act_stage_context_free (ctx); + nm_modem_get_uid (NM_MODEM (self))); + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_CONFIG_FAILED); + connect_context_clear (self); return; } - g_object_set (ctx->self, - NM_MODEM_DATA_PORT, mm_bearer_get_interface (ctx->self->priv->bearer), + g_object_set (self, + NM_MODEM_DATA_PORT, mm_bearer_get_interface (self->priv->bearer), NM_MODEM_IP4_METHOD, ip4_method, NM_MODEM_IP6_METHOD, ip6_method, - NM_MODEM_IP_TIMEOUT, mm_bearer_get_ip_timeout (ctx->self->priv->bearer), + NM_MODEM_IP_TIMEOUT, mm_bearer_get_ip_timeout (self->priv->bearer), NULL); - g_signal_emit_by_name (ctx->self, NM_MODEM_PREPARE_RESULT, TRUE, NM_DEVICE_STATE_REASON_NONE); - act_stage_context_free (ctx); + ctx->step++; + connect_context_step (self); } static void -act_stage_context_step (ActStageContext *ctx) +send_pin_ready (MMSim *sim, GAsyncResult *result, NMModemBroadband *self) { - if (ctx->ip_types_i < ctx->ip_types->len) { - NMModemIPType current; - - current = g_array_index (ctx->ip_types, NMModemIPType, ctx->ip_types_i); - - if (current == NM_MODEM_IP_TYPE_IPV4) - mm_simple_connect_properties_set_ip_type (ctx->connect_properties, MM_BEARER_IP_FAMILY_IPV4); - else if (current == NM_MODEM_IP_TYPE_IPV6) - mm_simple_connect_properties_set_ip_type (ctx->connect_properties, MM_BEARER_IP_FAMILY_IPV6); - else if (current == NM_MODEM_IP_TYPE_IPV4V6) - mm_simple_connect_properties_set_ip_type (ctx->connect_properties, MM_BEARER_IP_FAMILY_IPV4V6); - else - g_assert_not_reached (); - - nm_log_dbg (LOGD_MB, "(%s): launching connection with ip type '%s'", - nm_modem_get_uid (NM_MODEM (ctx->self)), - nm_modem_ip_type_to_string (current)); - - mm_modem_simple_connect (ctx->self->priv->simple_iface, - ctx->connect_properties, - NULL, - (GAsyncReadyCallback)connect_ready, - ctx); + GError *error = NULL; + + if (!mm_sim_send_pin_finish (sim, result, &error)) { + if (g_error_matches (error, MM_MOBILE_EQUIPMENT_ERROR, MM_MOBILE_EQUIPMENT_ERROR_SIM_PIN) || + (g_error_matches (error, MM_CORE_ERROR, MM_CORE_ERROR_UNAUTHORIZED) && + mm_modem_get_unlock_required (self->priv->modem_iface) == MM_MODEM_LOCK_SIM_PIN)) { + ask_for_pin (self); + } else { + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (error)); + } + g_error_free (error); return; + } + + self->priv->ctx->step++; + connect_context_step (self); +} + +static void +connect_context_step (NMModemBroadband *self) +{ + ConnectContext *ctx = self->priv->ctx; + + switch (ctx->step) { + case CONNECT_STEP_FIRST: + ctx->step++; + /* fall through */ + + case CONNECT_STEP_WAIT_FOR_SIM: + if (MODEM_CAPS_3GPP (ctx->caps) && !self->priv->sim_iface) { + /* Have to wait for the SIM to show up */ + break; + } + ctx->step++; + /* fall through */ + + case CONNECT_STEP_UNLOCK: + if ( MODEM_CAPS_3GPP (ctx->caps) + && mm_modem_get_unlock_required (self->priv->modem_iface) == MM_MODEM_LOCK_SIM_PIN) { + NMSettingGsm *s_gsm = nm_connection_get_setting_gsm (ctx->connection); + const char *pin = nm_setting_gsm_get_pin (s_gsm); + + /* If we have a PIN already, send it. If we don't, get it. */ + if (pin) { + mm_sim_send_pin (self->priv->sim_iface, + pin, + ctx->cancellable, + (GAsyncReadyCallback) send_pin_ready, + self); + } else { + ask_for_pin (self); + } + break; + } + ctx->step++; + /* fall through */ + + case CONNECT_STEP_WAIT_FOR_READY: { + GError *error = NULL; + + if (mm_modem_get_state (self->priv->modem_iface) <= MM_MODEM_STATE_LOCKED) + break; + + /* Create core connect properties based on the modem capabilities */ + g_assert (!ctx->connect_properties); + + if (MODEM_CAPS_3GPP (ctx->caps)) + ctx->connect_properties = create_gsm_connect_properties (ctx->connection); + else if (MODEM_CAPS_3GPP2 (ctx->caps)) + ctx->connect_properties = create_cdma_connect_properties (ctx->connection); + else { + nm_log_warn (LOGD_MB, "(%s): Failed to connect '%s': not a mobile broadband modem", + nm_modem_get_uid (NM_MODEM (self)), + nm_connection_get_id (ctx->connection)); + + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); + connect_context_clear (self); + break; + } + g_assert (ctx->connect_properties); + + /* Build up list of IP types that we need to use in the retries */ + ctx->ip_types = nm_modem_get_connection_ip_type (NM_MODEM (self), ctx->connection, &error); + if (!ctx->ip_types) { + nm_log_warn (LOGD_MB, "(%s): Failed to connect '%s': %s", + nm_modem_get_uid (NM_MODEM (self)), + nm_connection_get_id (ctx->connection), + error ? error->message : "unknown error"); + g_clear_error (&error); + + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED); + connect_context_clear (self); + break; + } + + ctx->step++; + /* fall through */ } - /* If we have a saved error from a previous attempt, use it */ - if (!ctx->first_error) - ctx->first_error = g_error_new_literal (NM_DEVICE_ERROR, - NM_DEVICE_ERROR_INVALID_CONNECTION, - "invalid bearer IP configuration"); - - nm_log_warn (LOGD_MB, "(%s): failed to connect modem: %s", - nm_modem_get_uid (NM_MODEM (ctx->self)), - ctx->first_error->message); - g_signal_emit_by_name (ctx->self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (ctx->first_error)); - act_stage_context_free (ctx); + case CONNECT_STEP_CONNECT: + if (ctx->ip_types_i < ctx->ip_types->len) { + NMModemIPType current; + + current = g_array_index (ctx->ip_types, NMModemIPType, ctx->ip_types_i); + + if (current == NM_MODEM_IP_TYPE_IPV4) + mm_simple_connect_properties_set_ip_type (ctx->connect_properties, MM_BEARER_IP_FAMILY_IPV4); + else if (current == NM_MODEM_IP_TYPE_IPV6) + mm_simple_connect_properties_set_ip_type (ctx->connect_properties, MM_BEARER_IP_FAMILY_IPV6); + else if (current == NM_MODEM_IP_TYPE_IPV4V6) + mm_simple_connect_properties_set_ip_type (ctx->connect_properties, MM_BEARER_IP_FAMILY_IPV4V6); + else + g_assert_not_reached (); + + nm_log_dbg (LOGD_MB, "(%s): launching connection with ip type '%s'", + nm_modem_get_uid (NM_MODEM (self)), + nm_modem_ip_type_to_string (current)); + + mm_modem_simple_connect (self->priv->simple_iface, + ctx->connect_properties, + NULL, + (GAsyncReadyCallback) connect_ready, + self); + break; + } + + ctx->step++; + /* fall through */ + + case CONNECT_STEP_LAST: + if (self->priv->ipv4_config || self->priv->ipv6_config) { + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, TRUE, NM_DEVICE_STATE_REASON_NONE); + } else { + /* If we have a saved error from a previous attempt, use it */ + if (!ctx->first_error) + ctx->first_error = g_error_new_literal (NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "invalid bearer IP configuration"); + + nm_log_warn (LOGD_MB, "(%s): failed to connect modem: %s", + nm_modem_get_uid (NM_MODEM (self)), + ctx->first_error->message); + g_signal_emit_by_name (self, NM_MODEM_PREPARE_RESULT, FALSE, translate_mm_error (ctx->first_error)); + } + + connect_context_clear (self); + break; + } } static NMActStageReturn @@ -393,8 +527,6 @@ act_stage1_prepare (NMModem *_self, NMDeviceStateReason *reason) { NMModemBroadband *self = NM_MODEM_BROADBAND (_self); - ActStageContext *ctx; - GError *error = NULL; /* Make sure we can get the Simple interface from the modem */ if (!self->priv->simple_iface) { @@ -407,41 +539,16 @@ act_stage1_prepare (NMModem *_self, } } - /* Allocate new context for this activation stage attempt */ - ctx = g_slice_new0 (ActStageContext); - ctx->self = NM_MODEM_BROADBAND (g_object_ref (self)); - ctx->caps = mm_modem_get_current_capabilities (self->priv->modem_iface); + connect_context_clear (self); - /* Create core connect properties based on the modem capabilities */ - if (MODEM_CAPS_3GPP (ctx->caps)) - ctx->connect_properties = create_gsm_connect_properties (connection); - else if (MODEM_CAPS_3GPP2 (ctx->caps)) - ctx->connect_properties = create_cdma_connect_properties (connection); - else { - nm_log_warn (LOGD_MB, "(%s): Failed to connect '%s': not a mobile broadband modem", - nm_modem_get_uid (NM_MODEM (self)), - nm_connection_get_id (connection)); - act_stage_context_free (ctx); - *reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; - } - g_assert (ctx->connect_properties); - - /* Checkout list of IP types that we need to use in the retries */ - ctx->ip_types = nm_modem_get_connection_ip_type (NM_MODEM (self), connection, &error); - if (!ctx->ip_types) { - nm_log_warn (LOGD_MB, "(%s): Failed to connect '%s': %s", - nm_modem_get_uid (NM_MODEM (self)), - nm_connection_get_id (connection), - error ? error->message : "unknown error"); - g_clear_error (&error); - act_stage_context_free (ctx); - *reason = NM_DEVICE_STATE_REASON_MODEM_INIT_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; - } + /* Allocate new context for this connect stage attempt */ + self->priv->ctx = g_slice_new0 (ConnectContext); + self->priv->ctx->caps = mm_modem_get_current_capabilities (self->priv->modem_iface); + self->priv->ctx->cancellable = g_cancellable_new (); + self->priv->ctx->connection = g_object_ref (connection); g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (self->priv->simple_iface), MODEM_CONNECT_TIMEOUT_SECS * 1000); - act_stage_context_step (ctx); + connect_context_step (self); return NM_ACT_STAGE_RETURN_POSTPONE; } @@ -715,6 +822,7 @@ static_stage3_ip4_done (NMModemBroadband *self) { GError *error = NULL; NMIP4Config *config = NULL; + const char *data_port; const gchar *address_string; const gchar *gw_string; guint32 address_network; @@ -724,6 +832,7 @@ static_stage3_ip4_done (NMModemBroadband *self) guint i; g_assert (self->priv->ipv4_config); + g_assert (self->priv->bearer); nm_log_info (LOGD_MB, "(%s): IPv4 static configuration:", nm_modem_get_uid (NM_MODEM (self))); @@ -743,10 +852,13 @@ static_stage3_ip4_done (NMModemBroadband *self) gw_string = mm_bearer_ip_config_get_gateway (self->priv->ipv4_config); ip4_string_to_num (gw_string, &gw); - config = nm_ip4_config_new (); + data_port = mm_bearer_get_interface (self->priv->bearer); + g_assert (data_port); + config = nm_ip4_config_new (nm_platform_link_get_ifindex (NM_PLATFORM_GET, data_port)); memset (&address, 0, sizeof (address)); address.address = address_network; + address.peer_address = address_network; address.plen = mm_bearer_ip_config_get_prefix (self->priv->ipv4_config); address.source = NM_IP_CONFIG_SOURCE_WWAN; nm_ip4_config_add_address (config, &address); @@ -796,6 +908,7 @@ stage3_ip6_done (NMModemBroadband *self) { GError *error = NULL; NMIP6Config *config = NULL; + const char *data_port; const gchar *address_string; NMPlatformIP6Address address; NMModemIPMethod ip_method; @@ -833,7 +946,9 @@ stage3_ip6_done (NMModemBroadband *self) nm_log_info (LOGD_MB, "(%s): IPv6 base configuration:", nm_modem_get_uid (NM_MODEM (self))); - config = nm_ip6_config_new (); + data_port = mm_bearer_get_interface (self->priv->bearer); + g_assert (data_port); + config = nm_ip6_config_new (nm_platform_link_get_ifindex (NM_PLATFORM_GET, data_port)); address.plen = mm_bearer_ip_config_get_prefix (self->priv->ipv6_config); nm_ip6_config_add_address (config, &address); @@ -941,10 +1056,11 @@ simple_disconnect_ready (MMModemSimple *modem_iface, GError *error = NULL; if (!mm_modem_simple_disconnect_finish (modem_iface, res, &error)) { - if (ctx->warn) + if (ctx->warn && !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN)) { nm_log_warn (LOGD_MB, "(%s) failed to disconnect modem: %s", nm_modem_get_uid (NM_MODEM (ctx->self)), error->message); + } g_simple_async_result_take_error (ctx->result, error); } @@ -1042,7 +1158,6 @@ modem_state_changed (MMModem *modem, MMModemStateChangeReason reason, NMModemBroadband *self) { - /* After the SIM is unlocked MM1 will move the device to INITIALIZING which * is an unavailable state. That makes state handling confusing here, so * suppress this state change and let the modem move from LOCKED to DISABLED. @@ -1053,6 +1168,9 @@ modem_state_changed (MMModem *modem, nm_modem_set_state (NM_MODEM (self), mm_state_to_nm (new_state), mm_modem_state_change_reason_get_string (reason)); + + if (self->priv->ctx && self->priv->ctx->step == CONNECT_STEP_WAIT_FOR_READY) + connect_context_step (self); } /*****************************************************************************/ @@ -1114,12 +1232,23 @@ get_sim_ready (MMModem *modem, GError *error = NULL; MMSim *new_sim; + new_sim = mm_modem_get_sim_finish (modem, res, &error); - if (new_sim) { + if (new_sim != self->priv->sim_iface) { + g_clear_object (&self->priv->sim_iface); + self->priv->sim_iface = new_sim; + } else + g_clear_object (&new_sim); + + if (self->priv->sim_iface) { g_object_set (G_OBJECT (self), - NM_MODEM_SIM_ID, mm_sim_get_identifier (new_sim), + NM_MODEM_SIM_ID, mm_sim_get_identifier (self->priv->sim_iface), + NM_MODEM_SIM_OPERATOR_ID, mm_sim_get_operator_identifier (self->priv->sim_iface), NULL); - g_object_unref (new_sim); + + /* If we're waiting for the SIM during a connect, proceed with the connect */ + if (self->priv->ctx && self->priv->ctx->step == CONNECT_STEP_WAIT_FOR_SIM) + connect_context_step (self); } else { nm_log_warn (LOGD_MB, "(%s): failed to retrieve SIM object: %s", nm_modem_get_uid (NM_MODEM (self)), @@ -1142,7 +1271,10 @@ sim_changed (MMModem *modem, GParamSpec *pspec, gpointer user_data) (GAsyncReadyCallback) get_sim_ready, g_object_ref (self)); } else - g_object_set (G_OBJECT (self), NM_MODEM_SIM_ID, NULL, NULL); + g_object_set (G_OBJECT (self), + NM_MODEM_SIM_ID, NULL, + NM_MODEM_SIM_OPERATOR_ID, NULL, + NULL); } static void @@ -1226,11 +1358,13 @@ dispose (GObject *object) { NMModemBroadband *self = NM_MODEM_BROADBAND (object); + connect_context_clear (self); g_clear_object (&self->priv->ipv4_config); g_clear_object (&self->priv->ipv6_config); g_clear_object (&self->priv->bearer); g_clear_object (&self->priv->modem_iface); g_clear_object (&self->priv->simple_iface); + g_clear_object (&self->priv->sim_iface); g_clear_object (&self->priv->modem_object); G_OBJECT_CLASS (nm_modem_broadband_parent_class)->dispose (object); diff --git a/src/devices/wwan/nm-modem-broadband.h b/src/devices/wwan/nm-modem-broadband.h index 2268bac4..a54e63a6 100644 --- a/src/devices/wwan/nm-modem-broadband.h +++ b/src/devices/wwan/nm-modem-broadband.h @@ -21,7 +21,6 @@ #ifndef __NETWORKMANAGER_MODEM_BROADBAND_H__ #define __NETWORKMANAGER_MODEM_BROADBAND_H__ -#include #include "nm-modem.h" G_BEGIN_DECLS diff --git a/src/devices/wwan/nm-modem-enum-types.c b/src/devices/wwan/nm-modem-enum-types.c index 6fbb3b6d..2d02ede9 100644 --- a/src/devices/wwan/nm-modem-enum-types.c +++ b/src/devices/wwan/nm-modem-enum-types.c @@ -3,6 +3,8 @@ /* Generated by glib-mkenums. Do not edit */ +#include "config.h" + #include "nm-modem-enum-types.h" #include "nm-modem.h" diff --git a/src/devices/wwan/nm-modem-manager.c b/src/devices/wwan/nm-modem-manager.c index f0e56926..c28d86ad 100644 --- a/src/devices/wwan/nm-modem-manager.c +++ b/src/devices/wwan/nm-modem-manager.c @@ -27,7 +27,8 @@ #include #include "nm-modem-manager.h" -#include "nm-logging.h" +#include "nm-default.h" +#include "nm-dbus-compat.h" #include "nm-modem.h" #include "nm-modem-broadband.h" @@ -193,10 +194,7 @@ modem_manager_name_owner_changed (MMManager *modem_manager, gchar *name_owner; /* Quit poking, if any */ - if (self->priv->mm_launch_id) { - g_source_remove (self->priv->mm_launch_id); - self->priv->mm_launch_id = 0; - } + nm_clear_g_source (&self->priv->mm_launch_id); name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (modem_manager)); if (!name_owner) { @@ -265,7 +263,7 @@ modem_manager_poke (NMModemManager *self) g_dbus_connection_call (self->priv->dbus_connection, "org.freedesktop.ModemManager1", "/org/freedesktop/ModemManager1", - "org.freedesktop.DBus.Peer", + DBUS_INTERFACE_PEER, "Ping", NULL, /* inputs */ NULL, /* outputs */ @@ -434,10 +432,7 @@ dispose (GObject *object) { NMModemManager *self = NM_MODEM_MANAGER (object); - if (self->priv->mm_launch_id) { - g_source_remove (self->priv->mm_launch_id); - self->priv->mm_launch_id = 0; - } + nm_clear_g_source (&self->priv->mm_launch_id); modem_manager_clear_signals (self); g_clear_object (&self->priv->modem_manager); diff --git a/src/devices/wwan/nm-modem-manager.h b/src/devices/wwan/nm-modem-manager.h index 9e0db41e..b0014c6a 100644 --- a/src/devices/wwan/nm-modem-manager.h +++ b/src/devices/wwan/nm-modem-manager.h @@ -23,7 +23,6 @@ #ifndef __NETWORKMANAGER_MODEM_MANAGER_H__ #define __NETWORKMANAGER_MODEM_MANAGER_H__ -#include #include "nm-modem.h" #define NM_TYPE_MODEM_MANAGER (nm_modem_manager_get_type ()) diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index 3385a6fd..15104307 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -22,17 +22,17 @@ #include "config.h" #include + #include "nm-modem.h" +#include "nm-core-internal.h" #include "nm-platform.h" -#include "nm-dbus-manager.h" #include "nm-setting-connection.h" -#include "nm-properties-changed-signal.h" -#include "nm-logging.h" +#include "nm-default.h" #include "NetworkManagerUtils.h" #include "nm-device-private.h" -#include "nm-dbus-glib-types.h" #include "nm-modem-enum-types.h" #include "nm-route-manager.h" +#include "gsystem-local-alloc.h" G_DEFINE_TYPE (NMModem, nm_modem, G_TYPE_OBJECT) @@ -52,6 +52,7 @@ enum { PROP_DEVICE_ID, PROP_SIM_ID, PROP_IP_TYPES, + PROP_SIM_OPERATOR_ID, LAST_PROP }; @@ -71,12 +72,13 @@ typedef struct { char *device_id; char *sim_id; NMModemIPType ip_types; + char *sim_operator_id; NMPPPManager *ppp_manager; NMActRequest *act_request; guint32 secrets_tries; - guint32 secrets_id; + NMActRequestGetSecretsCallId secrets_id; guint32 mm_ip_timeout; @@ -287,7 +289,7 @@ nm_modem_get_connection_ip_type (NMModem *self, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, "Connection requested IPv4 but IPv4 is " - "unsuported by the modem."); + "unsupported by the modem."); return NULL; } return build_single_ip_type_array (NM_MODEM_IP_TYPE_IPV4); @@ -299,7 +301,7 @@ nm_modem_get_connection_ip_type (NMModem *self, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, "Connection requested IPv6 but IPv6 is " - "unsuported by the modem."); + "unsupported by the modem."); return NULL; } return build_single_ip_type_array (NM_MODEM_IP_TYPE_IPV6); @@ -350,6 +352,24 @@ nm_modem_get_connection_ip_type (NMModem *self, return NULL; } +const char * +nm_modem_get_device_id (NMModem *self) +{ + return NM_MODEM_GET_PRIVATE (self)->device_id; +} + +const char * +nm_modem_get_sim_id (NMModem *self) +{ + return NM_MODEM_GET_PRIVATE (self)->sim_id; +} + +const char * +nm_modem_get_sim_operator_id (NMModem *self) +{ + return NM_MODEM_GET_PRIVATE (self)->sim_operator_id; +} + /*****************************************************************************/ /* IP method PPP */ @@ -493,7 +513,7 @@ ppp_stage3_ip_config_start (NMModem *self, return NM_ACT_STAGE_RETURN_POSTPONE; if (NM_MODEM_GET_CLASS (self)->get_user_pass) { - NMConnection *connection = nm_act_request_get_connection (req); + NMConnection *connection = nm_act_request_get_applied_connection (req); g_assert (connection); if (!NM_MODEM_GET_CLASS (self)->get_user_pass (self, connection, &ppp_name, NULL)) @@ -511,7 +531,7 @@ ppp_stage3_ip_config_start (NMModem *self, priv->ppp_manager = nm_ppp_manager_new (priv->data_port); if (nm_ppp_manager_start (priv->ppp_manager, req, ppp_name, ip_timeout, &error)) { - g_signal_connect (priv->ppp_manager, "state-changed", + g_signal_connect (priv->ppp_manager, NM_PPP_MANAGER_STATE_CHANGED, G_CALLBACK (ppp_state_changed), self); g_signal_connect (priv->ppp_manager, "ip4-config", @@ -532,8 +552,7 @@ ppp_stage3_ip_config_start (NMModem *self, error && error->message ? error->message : "(unknown)"); g_error_free (error); - g_object_unref (priv->ppp_manager); - priv->ppp_manager = NULL; + nm_exported_object_clear_and_unexport (&priv->ppp_manager); *reason = NM_DEVICE_STATE_REASON_PPP_START_FAILED; ret = NM_ACT_STAGE_RETURN_FAILURE; @@ -563,7 +582,7 @@ nm_modem_stage3_ip4_config_start (NMModem *self, req = nm_device_get_act_request (device); g_assert (req); - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); g_assert (connection); method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); @@ -680,7 +699,7 @@ nm_modem_stage3_ip6_config_start (NMModem *self, g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NM_ACT_STAGE_RETURN_FAILURE); g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); g_assert (connection); method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); @@ -725,16 +744,13 @@ cancel_get_secrets (NMModem *self) { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - if (priv->secrets_id) { - nm_act_request_cancel_secrets (priv->act_request, priv->secrets_id); - priv->secrets_id = 0; - } + nm_act_request_cancel_secrets (priv->act_request, priv->secrets_id); } static void modem_secrets_cb (NMActRequest *req, - guint32 call_id, - NMConnection *connection, + NMActRequestGetSecretsCallId call_id, + NMSettingsConnection *connection, GError *error, gpointer user_data) { @@ -743,7 +759,10 @@ modem_secrets_cb (NMActRequest *req, g_return_if_fail (call_id == priv->secrets_id); - priv->secrets_id = 0; + priv->secrets_id = NULL; + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; if (error) nm_log_warn (LOGD_MB, "(%s): %s", nm_modem_get_uid (self), error->message); @@ -751,7 +770,7 @@ modem_secrets_cb (NMActRequest *req, g_signal_emit (self, signals[AUTH_RESULT], 0, error); } -gboolean +void nm_modem_get_secrets (NMModem *self, const char *setting_name, gboolean request_new, @@ -770,10 +789,8 @@ nm_modem_get_secrets (NMModem *self, hint, modem_secrets_cb, self); - if (priv->secrets_id) - g_signal_emit (self, signals[AUTH_REQUESTED], 0); - - return !!(priv->secrets_id); + g_return_if_fail (priv->secrets_id); + g_signal_emit (self, signals[AUTH_REQUESTED], 0); } /*****************************************************************************/ @@ -793,8 +810,7 @@ nm_modem_act_stage1_prepare (NMModem *self, NMDeviceStateReason *reason) { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - NMActStageReturn ret; - GPtrArray *hints = NULL; + gs_unref_ptrarray GPtrArray *hints = NULL; const char *setting_name = NULL; NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; NMConnection *connection; @@ -803,7 +819,7 @@ nm_modem_act_stage1_prepare (NMModem *self, g_object_unref (priv->act_request); priv->act_request = g_object_ref (req); - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); g_assert (connection); setting_name = nm_connection_need_secrets (connection, &hints); @@ -823,18 +839,9 @@ nm_modem_act_stage1_prepare (NMModem *self, hints ? g_ptr_array_index (hints, 0) : NULL, modem_secrets_cb, self); - if (priv->secrets_id) { - g_signal_emit (self, signals[AUTH_REQUESTED], 0); - ret = NM_ACT_STAGE_RETURN_POSTPONE; - } else { - *reason = NM_DEVICE_STATE_REASON_NO_SECRETS; - ret = NM_ACT_STAGE_RETURN_FAILURE; - } - - if (hints) - g_ptr_array_free (hints, TRUE); - - return ret; + g_return_val_if_fail (priv->secrets_id, NM_ACT_STAGE_RETURN_FAILURE); + g_signal_emit (self, signals[AUTH_REQUESTED], 0); + return NM_ACT_STAGE_RETURN_POSTPONE; } /*****************************************************************************/ @@ -859,6 +866,67 @@ nm_modem_act_stage2_config (NMModem *self, gboolean nm_modem_check_connection_compatible (NMModem *self, NMConnection *connection) { + NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); + NMSettingConnection *s_con; + + s_con = nm_connection_get_setting_connection (connection); + g_assert (s_con); + + if (g_str_equal (nm_setting_connection_get_connection_type (s_con), + NM_SETTING_GSM_SETTING_NAME)) { + NMSettingGsm *s_gsm; + const char *str; + + s_gsm = nm_connection_get_setting_gsm (connection); + if (!s_gsm) + return FALSE; + + str = nm_setting_gsm_get_device_id (s_gsm); + if (str) { + if (!priv->device_id) { + nm_log_dbg (LOGD_MB, "(%s): %s/%s has device-id, device does not", + priv->uid, + nm_connection_get_uuid (connection), + nm_connection_get_id (connection)); + return FALSE; + } + if (strcmp (str, priv->device_id)) { + nm_log_dbg (LOGD_MB, "(%s): %s/%s device-id mismatch", + priv->uid, + nm_connection_get_uuid (connection), + nm_connection_get_id (connection)); + return FALSE; + } + } + + /* SIM properties may not be available before the SIM is unlocked, so + * to ensure that autoconnect works, the connection's SIM properties + * are only compared if present on the device. + */ + + str = nm_setting_gsm_get_sim_id (s_gsm); + if (str && priv->sim_id) { + if (strcmp (str, priv->sim_id)) { + nm_log_dbg (LOGD_MB, "(%s): %s/%s sim-id mismatch", + priv->uid, + nm_connection_get_uuid (connection), + nm_connection_get_id (connection)); + return FALSE; + } + } + + str = nm_setting_gsm_get_sim_operator_id (s_gsm); + if (str && priv->sim_operator_id) { + if (strcmp (str, priv->sim_operator_id)) { + nm_log_dbg (LOGD_MB, "(%s): %s/%s sim-operator-id mismatch", + priv->uid, + nm_connection_get_uuid (connection), + nm_connection_get_id (connection)); + return FALSE; + } + } + } + if (NM_MODEM_GET_CLASS (self)->check_connection_compatible) return NM_MODEM_GET_CLASS (self)->check_connection_compatible (self, connection); return FALSE; @@ -899,10 +967,7 @@ deactivate_cleanup (NMModem *self, NMDevice *device) priv->in_bytes = priv->out_bytes = 0; - if (priv->ppp_manager) { - g_object_unref (priv->ppp_manager); - priv->ppp_manager = NULL; - } + nm_exported_object_clear_and_unexport (&priv->ppp_manager); if (device) { g_return_if_fail (NM_IS_DEVICE (device)); @@ -1315,6 +1380,9 @@ get_property (GObject *object, guint prop_id, case PROP_IP_TYPES: g_value_set_uint (value, priv->ip_types); break; + case PROP_SIM_OPERATOR_ID: + g_value_set_string (value, priv->sim_operator_id); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1326,6 +1394,7 @@ set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (object); + const char *s; switch (prop_id) { case PROP_PATH: @@ -1369,6 +1438,12 @@ set_property (GObject *object, guint prop_id, case PROP_IP_TYPES: priv->ip_types = g_value_get_uint (value); break; + case PROP_SIM_OPERATOR_ID: + g_clear_pointer (&priv->sim_operator_id, g_free); + s = g_value_get_string (value); + if (s && s[0]) + priv->sim_operator_id = g_strdup (s); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1400,6 +1475,7 @@ finalize (GObject *object) g_free (priv->data_port); g_free (priv->device_id); g_free (priv->sim_id); + g_free (priv->sim_operator_id); G_OBJECT_CLASS (nm_modem_parent_class)->finalize (object); } @@ -1514,6 +1590,13 @@ nm_modem_class_init (NMModemClass *klass) 0, G_MAXUINT32, NM_MODEM_IP_TYPE_IPV4, G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + g_object_class_install_property + (object_class, PROP_SIM_OPERATOR_ID, + g_param_spec_string (NM_MODEM_SIM_OPERATOR_ID, "", "", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); + /* Signals */ signals[PPP_STATS] = diff --git a/src/devices/wwan/nm-modem.h b/src/devices/wwan/nm-modem.h index 2cace890..60e5589b 100644 --- a/src/devices/wwan/nm-modem.h +++ b/src/devices/wwan/nm-modem.h @@ -22,7 +22,7 @@ #ifndef __NETWORKMANAGER_MODEM_H__ #define __NETWORKMANAGER_MODEM_H__ -#include +#include "nm-default.h" #include "ppp-manager/nm-ppp-manager.h" #include "nm-device.h" @@ -36,18 +36,19 @@ G_BEGIN_DECLS #define NM_MODEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_MODEM, NMModemClass)) /* Properties */ -#define NM_MODEM_UID "uid" -#define NM_MODEM_PATH "path" -#define NM_MODEM_DRIVER "driver" -#define NM_MODEM_CONTROL_PORT "control-port" -#define NM_MODEM_DATA_PORT "data-port" -#define NM_MODEM_IP4_METHOD "ip4-method" -#define NM_MODEM_IP6_METHOD "ip6-method" -#define NM_MODEM_IP_TIMEOUT "ip-timeout" -#define NM_MODEM_STATE "state" -#define NM_MODEM_DEVICE_ID "device-id" -#define NM_MODEM_SIM_ID "sim-id" -#define NM_MODEM_IP_TYPES "ip-types" /* Supported IP types */ +#define NM_MODEM_UID "uid" +#define NM_MODEM_PATH "path" +#define NM_MODEM_DRIVER "driver" +#define NM_MODEM_CONTROL_PORT "control-port" +#define NM_MODEM_DATA_PORT "data-port" +#define NM_MODEM_IP4_METHOD "ip4-method" +#define NM_MODEM_IP6_METHOD "ip6-method" +#define NM_MODEM_IP_TIMEOUT "ip-timeout" +#define NM_MODEM_STATE "state" +#define NM_MODEM_DEVICE_ID "device-id" +#define NM_MODEM_SIM_ID "sim-id" +#define NM_MODEM_IP_TYPES "ip-types" /* Supported IP types */ +#define NM_MODEM_SIM_OPERATOR_ID "sim-operator-id" /* Signals */ #define NM_MODEM_PPP_STATS "ppp-stats" @@ -179,12 +180,15 @@ typedef struct { GType nm_modem_get_type (void); -const char *nm_modem_get_path (NMModem *modem); -const char *nm_modem_get_uid (NMModem *modem); -const char *nm_modem_get_control_port (NMModem *modem); -const char *nm_modem_get_data_port (NMModem *modem); -const char *nm_modem_get_driver (NMModem *modem); -gboolean nm_modem_get_iid (NMModem *modem, NMUtilsIPv6IfaceId *out_iid); +const char *nm_modem_get_path (NMModem *modem); +const char *nm_modem_get_uid (NMModem *modem); +const char *nm_modem_get_control_port (NMModem *modem); +const char *nm_modem_get_data_port (NMModem *modem); +const char *nm_modem_get_driver (NMModem *modem); +const char *nm_modem_get_device_id (NMModem *modem); +const char *nm_modem_get_sim_id (NMModem *modem); +const char *nm_modem_get_sim_operator_id (NMModem *modem); +gboolean nm_modem_get_iid (NMModem *modem, NMUtilsIPv6IfaceId *out_iid); gboolean nm_modem_owns_port (NMModem *modem, const char *iface); @@ -218,10 +222,10 @@ NMActStageReturn nm_modem_stage3_ip6_config_start (NMModem *modem, void nm_modem_ip4_pre_commit (NMModem *modem, NMDevice *device, NMIP4Config *config); -gboolean nm_modem_get_secrets (NMModem *modem, - const char *setting_name, - gboolean request_new, - const char *hint); +void nm_modem_get_secrets (NMModem *modem, + const char *setting_name, + gboolean request_new, + const char *hint); void nm_modem_deactivate (NMModem *modem, NMDevice *device); diff --git a/src/devices/wwan/nm-wwan-factory.c b/src/devices/wwan/nm-wwan-factory.c index 49b0b0af..2fd9e0bd 100644 --- a/src/devices/wwan/nm-wwan-factory.c +++ b/src/devices/wwan/nm-wwan-factory.c @@ -29,12 +29,12 @@ #include "nm-setting-cdma.h" #include "nm-modem-manager.h" #include "nm-device-modem.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-platform.h" static GType nm_wwan_factory_get_type (void); -static void device_factory_interface_init (NMDeviceFactory *factory_iface); +static void device_factory_interface_init (NMDeviceFactoryInterface *factory_iface); G_DEFINE_TYPE_EXTENDED (NMWwanFactory, nm_wwan_factory, G_TYPE_OBJECT, 0, G_IMPLEMENT_INTERFACE (NM_TYPE_DEVICE_FACTORY, device_factory_interface_init)) @@ -96,9 +96,14 @@ NM_DEVICE_FACTORY_DECLARE_TYPES ( ) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) +create_device (NMDeviceFactory *factory, + const char *iface, + const NMPlatformLink *plink, + NMConnection *connection, + gboolean *out_ignore) { - g_warn_if_fail (plink->type == NM_LINK_TYPE_WWAN_ETHERNET); + g_return_val_if_fail (plink, NULL); + g_return_val_if_fail (plink->type == NM_LINK_TYPE_WWAN_ETHERNET, NULL); *out_ignore = TRUE; return NULL; } @@ -123,10 +128,10 @@ nm_wwan_factory_init (NMWwanFactory *self) } static void -device_factory_interface_init (NMDeviceFactory *factory_iface) +device_factory_interface_init (NMDeviceFactoryInterface *factory_iface) { factory_iface->get_supported_types = get_supported_types; - factory_iface->new_link = new_link; + factory_iface->create_device = create_device; factory_iface->start = start; } diff --git a/src/devices/wwan/nm-wwan-factory.h b/src/devices/wwan/nm-wwan-factory.h index c6c03f1f..78031e60 100644 --- a/src/devices/wwan/nm-wwan-factory.h +++ b/src/devices/wwan/nm-wwan-factory.h @@ -21,7 +21,7 @@ #ifndef __NETWORKMANAGER_WWAN_FACTORY_H__ #define __NETWORKMANAGER_WWAN_FACTORY_H__ -#include +#include "nm-default.h" #define NM_TYPE_WWAN_FACTORY (nm_wwan_factory_get_type ()) #define NM_WWAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_WWAN_FACTORY, NMWwanFactory)) diff --git a/src/dhcp-manager/Makefile.am b/src/dhcp-manager/Makefile.am index 27945f55..3199ab04 100644 --- a/src/dhcp-manager/Makefile.am +++ b/src/dhcp-manager/Makefile.am @@ -4,20 +4,12 @@ nm_dhcp_helper_SOURCES = nm-dhcp-helper.c nm_dhcp_helper_CPPFLAGS = \ $(GLIB_CFLAGS) \ + -I$(top_srcdir)/shared \ + -I${top_builddir}/shared \ + -I$(top_srcdir)/libnm-core \ + -I$(top_builddir)/libnm-core \ -DG_LOG_DOMAIN=\""nm-dhcp-helper"\" \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ -DNMRUNDIR=\"$(nmrundir)\" nm_dhcp_helper_LDADD = $(GLIB_LIBS) - - -# FIXME: remove when dbus-glib >= 0.100 or GDBus is required -dhcp_helper_conf = nm-dhcp-helper.conf - -if !HAVE_DBUS_GLIB_100 -dbusservicedir = $(DBUS_SYS_DIR) -dbusservice_DATA = $(dhcp_helper_conf) -endif - -EXTRA_DIST = $(dhcp_helper_conf) - diff --git a/src/dhcp-manager/Makefile.in b/src/dhcp-manager/Makefile.in index 6a2cad49..35ee4822 100644 --- a/src/dhcp-manager/Makefile.in +++ b/src/dhcp-manager/Makefile.in @@ -14,7 +14,6 @@ @SET_MAKE@ - VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ @@ -112,8 +111,7 @@ mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = -am__installdirs = "$(DESTDIR)$(libexecdir)" \ - "$(DESTDIR)$(dbusservicedir)" +am__installdirs = "$(DESTDIR)$(libexecdir)" PROGRAMS = $(libexec_PROGRAMS) am_nm_dhcp_helper_OBJECTS = nm_dhcp_helper-nm-dhcp-helper.$(OBJEXT) nm_dhcp_helper_OBJECTS = $(am_nm_dhcp_helper_OBJECTS) @@ -164,34 +162,6 @@ am__can_run_installinfo = \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -DATA = $(dbusservice_DATA) 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 @@ -229,7 +199,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -241,8 +210,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -252,6 +219,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -306,16 +274,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -352,6 +317,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -380,7 +347,6 @@ 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@ @@ -395,6 +361,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -455,6 +423,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -462,6 +431,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -480,17 +450,15 @@ with_valgrind = @with_valgrind@ nm_dhcp_helper_SOURCES = nm-dhcp-helper.c nm_dhcp_helper_CPPFLAGS = \ $(GLIB_CFLAGS) \ + -I$(top_srcdir)/shared \ + -I${top_builddir}/shared \ + -I$(top_srcdir)/libnm-core \ + -I$(top_builddir)/libnm-core \ -DG_LOG_DOMAIN=\""nm-dhcp-helper"\" \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ -DNMRUNDIR=\"$(nmrundir)\" nm_dhcp_helper_LDADD = $(GLIB_LIBS) - -# FIXME: remove when dbus-glib >= 0.100 or GDBus is required -dhcp_helper_conf = nm-dhcp-helper.conf -@HAVE_DBUS_GLIB_100_FALSE@dbusservicedir = $(DBUS_SYS_DIR) -@HAVE_DBUS_GLIB_100_FALSE@dbusservice_DATA = $(dhcp_helper_conf) -EXTRA_DIST = $(dhcp_helper_conf) all: all-am .SUFFIXES: @@ -626,27 +594,6 @@ mostlyclean-libtool: clean-libtool: -rm -rf .libs _libs -install-dbusserviceDATA: $(dbusservice_DATA) - @$(NORMAL_INSTALL) - @list='$(dbusservice_DATA)'; test -n "$(dbusservicedir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(dbusservicedir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(dbusservicedir)" || exit 1; \ - fi; \ - for p in $$list; do \ - if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ - echo "$$d$$p"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dbusservicedir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(dbusservicedir)" || exit $$?; \ - done - -uninstall-dbusserviceDATA: - @$(NORMAL_UNINSTALL) - @list='$(dbusservice_DATA)'; test -n "$(dbusservicedir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - dir='$(DESTDIR)$(dbusservicedir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique @@ -732,9 +679,9 @@ distdir: $(DISTFILES) done check-am: all-am check: check-am -all-am: Makefile $(PROGRAMS) $(DATA) +all-am: Makefile $(PROGRAMS) installdirs: - for dir in "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(dbusservicedir)"; do \ + for dir in "$(DESTDIR)$(libexecdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am @@ -790,7 +737,7 @@ info: info-am info-am: -install-data-am: install-dbusserviceDATA +install-data-am: install-dvi: install-dvi-am @@ -836,7 +783,7 @@ ps: ps-am ps-am: -uninstall-am: uninstall-dbusserviceDATA uninstall-libexecPROGRAMS +uninstall-am: uninstall-libexecPROGRAMS .MAKE: install-am install-strip @@ -845,15 +792,14 @@ uninstall-am: uninstall-dbusserviceDATA uninstall-libexecPROGRAMS 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-dbusserviceDATA install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-info install-info-am \ - install-libexecPROGRAMS 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 uninstall-dbusserviceDATA \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libexecPROGRAMS 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 \ uninstall-libexecPROGRAMS .PRECIOUS: Makefile diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c index 7f5d5a28..59c69c2a 100644 --- a/src/dhcp-manager/nm-dhcp-client.c +++ b/src/dhcp-manager/nm-dhcp-client.c @@ -19,7 +19,6 @@ #include "config.h" -#include #include #include #include @@ -29,10 +28,9 @@ #include #include +#include "nm-default.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" -#include "nm-logging.h" -#include "nm-dbus-glib-types.h" #include "nm-dhcp-client.h" #include "nm-dhcp-utils.h" #include "nm-platform.h" @@ -49,6 +47,7 @@ typedef struct { GByteArray * duid; GBytes * client_id; char * hostname; + char * fqdn; NMDhcpState state; pid_t pid; @@ -178,6 +177,14 @@ nm_dhcp_client_get_hostname (NMDhcpClient *self) return NM_DHCP_CLIENT_GET_PRIVATE (self)->hostname; } +const char * +nm_dhcp_client_get_fqdn (NMDhcpClient *self) +{ + g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL); + + return NM_DHCP_CLIENT_GET_PRIVATE (self)->fqdn; +} + /********************************************/ static const char *state_table[NM_DHCP_STATE_MAX + 1] = { @@ -231,10 +238,7 @@ timeout_cleanup (NMDhcpClient *self) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); - if (priv->timeout_id) { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } + nm_clear_g_source (&priv->timeout_id); } static void @@ -242,10 +246,7 @@ watch_cleanup (NMDhcpClient *self) { NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE (self); - if (priv->watch_id) { - g_source_remove (priv->watch_id); - priv->watch_id = 0; - } + nm_clear_g_source (&priv->watch_id); } void @@ -410,6 +411,7 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self, const char *dhcp_client_id, const char *dhcp_anycast_addr, const char *hostname, + const char *fqdn, const char *last_ip4_address) { NMDhcpClientPrivate *priv; @@ -428,6 +430,8 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self, g_clear_pointer (&priv->hostname, g_free); priv->hostname = g_strdup (hostname); + g_free (priv->fqdn); + priv->fqdn = g_strdup (fqdn); return NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, dhcp_anycast_addr, last_ip4_address); } @@ -547,6 +551,7 @@ get_duid (NMDhcpClient *self) gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self, const char *dhcp_anycast_addr, + const struct in6_addr *ll_addr, const char *hostname, gboolean info_only, NMSettingIP6ConfigPrivacy privacy) @@ -583,6 +588,7 @@ nm_dhcp_client_start_ip6 (NMDhcpClient *self, return NM_DHCP_CLIENT_GET_CLASS (self)->ip6_start (self, dhcp_anycast_addr, + ll_addr, info_only, privacy, priv->duid); @@ -662,21 +668,25 @@ nm_dhcp_client_stop (NMDhcpClient *self, gboolean release) /********************************************/ static char * -garray_to_string (GArray *array, const char *key) +bytearray_variant_to_string (GVariant *value, const char *key) { + const guint8 *array; + gsize length; GString *str; int i; unsigned char c; char *converted = NULL; - g_return_val_if_fail (array != NULL, NULL); + g_return_val_if_fail (value != NULL, NULL); + + array = g_variant_get_fixed_array (value, &length, 1); /* Since the DHCP options come through environment variables, they should * already be UTF-8 safe, but just make sure. */ - str = g_string_sized_new (array->len); - for (i = 0; i < array->len; i++) { - c = array->data[i]; + str = g_string_sized_new (length); + for (i = 0; i < length; i++) { + c = array[i]; /* Convert NULLs to spaces and non-ASCII characters to ? */ if (c == '\0') @@ -698,11 +708,10 @@ garray_to_string (GArray *array, const char *key) #define NEW_TAG "new_" static void -copy_option (const char * key, - GValue *value, - gpointer user_data) +maybe_add_option (GHashTable *hash, + const char *key, + GVariant *value) { - GHashTable *hash = user_data; char *str_value = NULL; const char **p; static const char *ignored_keys[] = { @@ -713,10 +722,7 @@ copy_option (const char * key, NULL }; - if (!G_VALUE_HOLDS (value, DBUS_TYPE_G_UCHAR_ARRAY)) { - nm_log_warn (LOGD_DHCP, "key %s value type was not DBUS_TYPE_G_UCHAR_ARRAY", key); - return; - } + g_return_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE_BYTESTRING)); if (g_str_has_prefix (key, OLD_TAG)) return; @@ -732,7 +738,7 @@ copy_option (const char * key, if (!key[0]) return; - str_value = garray_to_string ((GArray *) g_value_get_boxed (value), key); + str_value = bytearray_variant_to_string (value, key); if (str_value) g_hash_table_insert (hash, g_strdup (key), str_value); } @@ -741,7 +747,7 @@ gboolean nm_dhcp_client_handle_event (gpointer unused, const char *iface, gint pid, - GHashTable *options, + GVariant *options, const char *reason, NMDhcpClient *self) { @@ -754,7 +760,7 @@ nm_dhcp_client_handle_event (gpointer unused, g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), FALSE); g_return_val_if_fail (iface != NULL, FALSE); g_return_val_if_fail (pid > 0, FALSE); - g_return_val_if_fail (options != NULL, FALSE); + g_return_val_if_fail (g_variant_is_of_type (options, G_VARIANT_TYPE_VARDICT), FALSE); g_return_val_if_fail (reason != NULL, FALSE); priv = NM_DHCP_CLIENT_GET_PRIVATE (self); @@ -770,20 +776,30 @@ nm_dhcp_client_handle_event (gpointer unused, iface, reason, state_to_string (new_state)); if (new_state == NM_DHCP_STATE_BOUND) { + GVariantIter iter; + const char *name; + GVariant *value; + /* Copy options */ str_options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - g_hash_table_foreach (options, (GHFunc) copy_option, str_options); + g_variant_iter_init (&iter, options); + while (g_variant_iter_next (&iter, "{&sv}", &name, &value)) { + maybe_add_option (str_options, name, value); + g_variant_unref (value); + } /* Create the IP config */ g_warn_if_fail (g_hash_table_size (str_options)); if (g_hash_table_size (str_options)) { if (priv->ipv6) { - ip_config = (GObject *) nm_dhcp_utils_ip6_config_from_options (priv->iface, + ip_config = (GObject *) nm_dhcp_utils_ip6_config_from_options (priv->ifindex, + priv->iface, str_options, priv->priority, priv->info_only); } else { - ip_config = (GObject *) nm_dhcp_utils_ip4_config_from_options (priv->iface, + ip_config = (GObject *) nm_dhcp_utils_ip4_config_from_options (priv->ifindex, + priv->iface, str_options, priv->priority); } diff --git a/src/dhcp-manager/nm-dhcp-client.h b/src/dhcp-manager/nm-dhcp-client.h index 971c9dc0..7e28391d 100644 --- a/src/dhcp-manager/nm-dhcp-client.h +++ b/src/dhcp-manager/nm-dhcp-client.h @@ -19,14 +19,13 @@ #ifndef __NETWORKMANAGER_DHCP_CLIENT_H__ #define __NETWORKMANAGER_DHCP_CLIENT_H__ -#include -#include - #include #include #include #include +#include "nm-default.h" + #define NM_TYPE_DHCP_CLIENT (nm_dhcp_client_get_type ()) #define NM_DHCP_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP_CLIENT, NMDhcpClient)) #define NM_DHCP_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DHCP_CLIENT, NMDhcpClientClass)) @@ -70,6 +69,7 @@ typedef struct { gboolean (*ip6_start) (NMDhcpClient *self, const char *anycast_addr, + const struct in6_addr *ll_addr, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, const GByteArray *duid); @@ -101,6 +101,7 @@ GType nm_dhcp_client_get_type (void); typedef const char *(*NMDhcpClientGetPathFunc) (void); typedef GSList * (*NMDhcpClientGetLeaseConfigsFunc) (const char *iface, + int ifindex, const char *uuid, gboolean ipv6, guint32 default_route_metric); @@ -130,14 +131,18 @@ GBytes *nm_dhcp_client_get_client_id (NMDhcpClient *self); const char *nm_dhcp_client_get_hostname (NMDhcpClient *self); +const char *nm_dhcp_client_get_fqdn (NMDhcpClient *self); + gboolean nm_dhcp_client_start_ip4 (NMDhcpClient *self, const char *dhcp_client_id, const char *dhcp_anycast_addr, const char *hostname, + const char *fqdn, const char *last_ip4_address); gboolean nm_dhcp_client_start_ip6 (NMDhcpClient *self, const char *dhcp_anycast_addr, + const struct in6_addr *ll_addr, const char *hostname, gboolean info_only, NMSettingIP6ConfigPrivacy privacy); @@ -159,7 +164,7 @@ void nm_dhcp_client_set_state (NMDhcpClient *self, gboolean nm_dhcp_client_handle_event (gpointer unused, const char *iface, gint pid, - GHashTable *options, + GVariant *options, const char *reason, NMDhcpClient *self); diff --git a/src/dhcp-manager/nm-dhcp-dhclient-utils.c b/src/dhcp-manager/nm-dhcp-dhclient-utils.c index 41ce5354..5340d21a 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient-utils.c +++ b/src/dhcp-manager/nm-dhcp-dhclient-utils.c @@ -19,19 +19,17 @@ #include "config.h" -#include -#include #include #include #include +#include "nm-default.h" #include "nm-dhcp-dhclient-utils.h" #include "nm-dhcp-utils.h" #include "nm-ip4-config.h" #include "nm-utils.h" #include "nm-platform.h" #include "NetworkManagerUtils.h" -#include "gsystem-local-alloc.h" #include "nm-macros-internal.h" #define CLIENTID_TAG "send dhcp-client-identifier" @@ -57,24 +55,29 @@ add_also_request (GPtrArray *array, const char *item) } static void -add_hostname4 (GString *str, const char *format, const char *hostname) +add_hostname4 (GString *str, const char *hostname, const char *fqdn) { char *plain_hostname, *dot; - if (hostname) { + if (fqdn) { + g_string_append_printf (str, FQDN_FORMAT "\n", fqdn); + g_string_append (str, + "send fqdn.encoded on;\n" + "send fqdn.server-update on;\n"); + } else if (hostname) { plain_hostname = g_strdup (hostname); dot = strchr (plain_hostname, '.'); /* get rid of the domain */ if (dot) *dot = '\0'; - g_string_append_printf (str, format, plain_hostname); + g_string_append_printf (str, HOSTNAME4_FORMAT "\n", plain_hostname); g_free (plain_hostname); } } static void -add_ip4_config (GString *str, GBytes *client_id, const char *hostname) +add_ip4_config (GString *str, GBytes *client_id, const char *hostname, const char *fqdn) { if (client_id) { const char *p; @@ -109,7 +112,7 @@ add_ip4_config (GString *str, GBytes *client_id, const char *hostname) g_string_append (str, "; # added by NetworkManager\n"); } - add_hostname4 (str, HOSTNAME4_FORMAT "\n", hostname); + add_hostname4 (str, hostname, fqdn); g_string_append_c (str, '\n'); @@ -197,6 +200,7 @@ nm_dhcp_dhclient_create_config (const char *interface, GBytes *client_id, const char *anycast_addr, const char *hostname, + const char *fqdn, const char *orig_path, const char *orig_contents, GBytes **out_new_client_id) @@ -234,7 +238,7 @@ nm_dhcp_dhclient_create_config (const char *interface, } /* Override config file hostname and use one from the connection */ - if (hostname) { + if (hostname || fqdn) { if (strncmp (p, HOSTNAME4_TAG, strlen (HOSTNAME4_TAG)) == 0) continue; if (strncmp (p, FQDN_TAG, strlen (FQDN_TAG)) == 0) @@ -300,7 +304,7 @@ nm_dhcp_dhclient_create_config (const char *interface, add_also_request (alsoreq, "dhcp6.domain-search"); add_also_request (alsoreq, "dhcp6.client-id"); } else { - add_ip4_config (new_contents, client_id, hostname); + add_ip4_config (new_contents, client_id, hostname, fqdn); add_also_request (alsoreq, "rfc3442-classless-static-routes"); add_also_request (alsoreq, "ms-classless-static-routes"); add_also_request (alsoreq, "static-routes"); @@ -576,6 +580,7 @@ lease_validity_span (const char *str_expire, GDateTime *now) /** * nm_dhcp_dhclient_read_lease_ip_configs: * @iface: the interface name to match leases with + * @ifindex: interface index of @iface * @contents: the contents of a dhclient leasefile * @ipv6: whether to read IPv4 or IPv6 leases * @now: the current UTC date/time; pass %NULL to automatically use current @@ -589,6 +594,7 @@ lease_validity_span (const char *str_expire, GDateTime *now) */ GSList * nm_dhcp_dhclient_read_lease_ip_configs (const char *iface, + int ifindex, const char *contents, gboolean ipv6, GDateTime *now) @@ -675,6 +681,7 @@ nm_dhcp_dhclient_read_lease_ip_configs (const char *iface, continue; if (!inet_pton (AF_INET, value, &address.address)) continue; + address.peer_address = address.address; /* Gateway */ value = g_hash_table_lookup (hash, "option routers"); @@ -696,7 +703,7 @@ nm_dhcp_dhclient_read_lease_ip_configs (const char *iface, address.lifetime = address.preferred = expiry; address.source = NM_IP_CONFIG_SOURCE_DHCP; - ip4 = nm_ip4_config_new (); + ip4 = nm_ip4_config_new (ifindex); nm_ip4_config_add_address (ip4, &address); nm_ip4_config_set_gateway (ip4, gw); diff --git a/src/dhcp-manager/nm-dhcp-dhclient-utils.h b/src/dhcp-manager/nm-dhcp-dhclient-utils.h index a1828add..0e255027 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient-utils.h +++ b/src/dhcp-manager/nm-dhcp-dhclient-utils.h @@ -19,17 +19,17 @@ #ifndef __NETWORKMANAGER_DHCP_DHCLIENT_UTILS_H__ #define __NETWORKMANAGER_DHCP_DHCLIENT_UTILS_H__ -#include -#include - #include #include +#include "nm-default.h" + char *nm_dhcp_dhclient_create_config (const char *interface, gboolean is_ip6, GBytes *client_id, const char *anycast_addr, const char *hostname, + const char *fqdn, const char *orig_path, const char *orig_contents, GBytes **out_new_client_id); @@ -45,6 +45,7 @@ gboolean nm_dhcp_dhclient_save_duid (const char *leasefile, GError **error); GSList *nm_dhcp_dhclient_read_lease_ip_configs (const char *iface, + int ifindex, const char *contents, gboolean ipv6, GDateTime *now); diff --git a/src/dhcp-manager/nm-dhcp-dhclient.c b/src/dhcp-manager/nm-dhcp-dhclient.c index 91515dda..972fb506 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient.c +++ b/src/dhcp-manager/nm-dhcp-dhclient.c @@ -24,9 +24,6 @@ #include #undef _XOPEN_SOURCE -#include -#include -#include #include #include #include @@ -36,14 +33,13 @@ #include #include +#include "nm-default.h" #include "nm-dhcp-dhclient.h" #include "nm-utils.h" -#include "nm-logging.h" #include "nm-dhcp-dhclient-utils.h" #include "nm-dhcp-manager.h" #include "NetworkManagerUtils.h" #include "nm-dhcp-listener.h" -#include "gsystem-local-alloc.h" G_DEFINE_TYPE (NMDhcpDhclient, nm_dhcp_dhclient, NM_TYPE_DHCP_CLIENT) @@ -125,6 +121,7 @@ get_dhclient_leasefile (const char *iface, static GSList * nm_dhcp_dhclient_get_lease_ip_configs (const char *iface, + int ifindex, const char *uuid, gboolean ipv6, guint32 default_route_metric) @@ -141,7 +138,7 @@ nm_dhcp_dhclient_get_lease_ip_configs (const char *iface, && g_file_get_contents (leasefile, &contents, NULL, NULL) && contents && contents[0]) - leases = nm_dhcp_dhclient_read_lease_ip_configs (iface, contents, ipv6, NULL); + leases = nm_dhcp_dhclient_read_lease_ip_configs (iface, ifindex, contents, ipv6, NULL); g_free (leasefile); g_free (contents); @@ -156,6 +153,7 @@ merge_dhclient_config (const char *iface, GBytes *client_id, const char *anycast_addr, const char *hostname, + const char *fqdn, const char *orig_path, GBytes **out_new_client_id, GError **error) @@ -176,7 +174,7 @@ merge_dhclient_config (const char *iface, } } - new = nm_dhcp_dhclient_create_config (iface, is_ip6, client_id, anycast_addr, hostname, orig_path, orig, out_new_client_id); + new = nm_dhcp_dhclient_create_config (iface, is_ip6, client_id, anycast_addr, hostname, fqdn, orig_path, orig, out_new_client_id); g_assert (new); success = g_file_set_contents (conf_file, new, -1, error); g_free (new); @@ -263,6 +261,7 @@ create_dhclient_config (const char *iface, GBytes *client_id, const char *dhcp_anycast_addr, const char *hostname, + const char *fqdn, GBytes **out_new_client_id) { char *orig = NULL, *new = NULL; @@ -288,7 +287,7 @@ create_dhclient_config (const char *iface, } error = NULL; - success = merge_dhclient_config (iface, new, is_ip6, client_id, dhcp_anycast_addr, hostname, orig, out_new_client_id, &error); + success = merge_dhclient_config (iface, new, is_ip6, client_id, dhcp_anycast_addr, hostname, fqdn, orig, out_new_client_id, &error); if (!success) { nm_log_warn (LOGD_DHCP, "(%s): error creating dhclient%s configuration: %s", iface, is_ip6 ? "6" : "", error->message); @@ -331,7 +330,7 @@ dhclient_start (NMDhcpClient *client, return FALSE; } - pid_file = g_strdup_printf (LOCALSTATEDIR "/run/dhclient%s-%s.pid", + pid_file = g_strdup_printf (RUNSTATEDIR "/dhclient%s-%s.pid", ipv6 ? "6" : "", iface); @@ -468,15 +467,17 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last NMDhcpDhclientPrivate *priv = NM_DHCP_DHCLIENT_GET_PRIVATE (client); GBytes *client_id; gs_unref_bytes GBytes *new_client_id = NULL; - const char *iface, *uuid, *hostname; + const char *iface, *uuid, *hostname, *fqdn; gboolean success = FALSE; iface = nm_dhcp_client_get_iface (client); uuid = nm_dhcp_client_get_uuid (client); client_id = nm_dhcp_client_get_client_id (client); hostname = nm_dhcp_client_get_hostname (client); + fqdn = nm_dhcp_client_get_fqdn (client); - priv->conf_file = create_dhclient_config (iface, FALSE, uuid, client_id, dhcp_anycast_addr, hostname, &new_client_id); + priv->conf_file = create_dhclient_config (iface, FALSE, uuid, client_id, dhcp_anycast_addr, + hostname, fqdn, &new_client_id); if (priv->conf_file) { if (new_client_id) nm_dhcp_client_set_client_id (client, new_client_id); @@ -490,6 +491,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last static gboolean ip6_start (NMDhcpClient *client, const char *dhcp_anycast_addr, + const struct in6_addr *ll_addr, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, const GByteArray *duid) @@ -501,7 +503,7 @@ ip6_start (NMDhcpClient *client, uuid = nm_dhcp_client_get_uuid (client); hostname = nm_dhcp_client_get_hostname (client); - priv->conf_file = create_dhclient_config (iface, TRUE, uuid, NULL, dhcp_anycast_addr, hostname, NULL); + priv->conf_file = create_dhclient_config (iface, TRUE, uuid, NULL, dhcp_anycast_addr, hostname, NULL, NULL); if (!priv->conf_file) { nm_log_warn (LOGD_DHCP6, "(%s): error creating dhclient6 configuration file.", iface); return FALSE; @@ -668,7 +670,7 @@ nm_dhcp_dhclient_class_init (NMDhcpDhclientClass *dhclient_class) static void __attribute__((constructor)) register_dhcp_dhclient (void) { - g_type_init (); + nm_g_type_init (); _nm_dhcp_client_register (NM_TYPE_DHCP_DHCLIENT, "dhclient", nm_dhcp_dhclient_get_path, diff --git a/src/dhcp-manager/nm-dhcp-dhclient.h b/src/dhcp-manager/nm-dhcp-dhclient.h index 5abcc08e..3e8d9c5d 100644 --- a/src/dhcp-manager/nm-dhcp-dhclient.h +++ b/src/dhcp-manager/nm-dhcp-dhclient.h @@ -19,9 +19,7 @@ #ifndef __NETWORKMANAGER_DHCP_DHCLIENT_H__ #define __NETWORKMANAGER_DHCP_DHCLIENT_H__ -#include -#include - +#include "nm-default.h" #include "nm-dhcp-client.h" #define NM_TYPE_DHCP_DHCLIENT (nm_dhcp_dhclient_get_type ()) diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.c b/src/dhcp-manager/nm-dhcp-dhcpcd.c index 86aba4da..ebbbb081 100644 --- a/src/dhcp-manager/nm-dhcp-dhcpcd.c +++ b/src/dhcp-manager/nm-dhcp-dhcpcd.c @@ -23,8 +23,6 @@ #include "config.h" -#include -#include #include #include #include @@ -33,10 +31,10 @@ #include #include +#include "nm-default.h" #include "nm-dhcp-dhcpcd.h" #include "nm-dhcp-manager.h" #include "nm-utils.h" -#include "nm-logging.h" #include "NetworkManagerUtils.h" #include "nm-dhcp-listener.h" @@ -65,8 +63,9 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last GPtrArray *argv = NULL; pid_t pid = -1; GError *error = NULL; - char *pid_contents = NULL, *binary_name, *cmd_str; - const char *iface, *dhcpcd_path, *hostname; + char *pid_contents = NULL, *binary_name, *cmd_str, *dot; + const char *iface, *dhcpcd_path, *hostname, *fqdn; + gs_free char *prefix = NULL; g_return_val_if_fail (priv->pid_file == NULL, FALSE); @@ -95,7 +94,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last g_ptr_array_add (argv, (gpointer) "-K"); /* Disable built-in carrier detection */ - g_ptr_array_add (argv, (gpointer) "-L"); /* Disable built-in IPv4LL since we use avahi-autoipd */ + g_ptr_array_add (argv, (gpointer) "-L"); /* Disable built-in IPv4LL */ /* --noarp. Don't request or claim the address by ARP; this also disables IPv4LL. */ g_ptr_array_add (argv, (gpointer) "-A"); @@ -114,9 +113,22 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last #endif hostname = nm_dhcp_client_get_hostname (client); - if (hostname) { + fqdn = nm_dhcp_client_get_fqdn (client); + + if (fqdn) { + g_ptr_array_add (argv, (gpointer) "-h"); + g_ptr_array_add (argv, (gpointer) fqdn); + g_ptr_array_add (argv, (gpointer) "-F"); + g_ptr_array_add (argv, (gpointer) "both"); + } else if (hostname) { + prefix = strdup (hostname); + dot = strchr (prefix, '.'); + /* get rid of the domain */ + if (dot) + *dot = '\0'; + g_ptr_array_add (argv, (gpointer) "-h"); /* Send hostname to DHCP server */ - g_ptr_array_add (argv, (gpointer) hostname ); + g_ptr_array_add (argv, (gpointer) prefix); } g_ptr_array_add (argv, (gpointer) iface); @@ -145,6 +157,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last static gboolean ip6_start (NMDhcpClient *client, const char *dhcp_anycast_addr, + const struct in6_addr *ll_addr, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, const GByteArray *duid) @@ -213,7 +226,7 @@ nm_dhcp_dhcpcd_class_init (NMDhcpDhcpcdClass *dhcpcd_class) static void __attribute__((constructor)) register_dhcp_dhclient (void) { - g_type_init (); + nm_g_type_init (); _nm_dhcp_client_register (NM_TYPE_DHCP_DHCPCD, "dhcpcd", nm_dhcp_dhcpcd_get_path, diff --git a/src/dhcp-manager/nm-dhcp-dhcpcd.h b/src/dhcp-manager/nm-dhcp-dhcpcd.h index deed70e0..6f15ad22 100644 --- a/src/dhcp-manager/nm-dhcp-dhcpcd.h +++ b/src/dhcp-manager/nm-dhcp-dhcpcd.h @@ -19,9 +19,6 @@ #ifndef __NETWORKMANAGER_DHCP_DHCPCD_H__ #define __NETWORKMANAGER_DHCP_DHCPCD_H__ -#include -#include - #include "nm-dhcp-client.h" #define NM_TYPE_DHCP_DHCPCD (nm_dhcp_dhcpcd_get_type ()) diff --git a/src/dhcp-manager/nm-dhcp-helper.c b/src/dhcp-manager/nm-dhcp-helper.c index 5bcb0e27..15b63d94 100644 --- a/src/dhcp-manager/nm-dhcp-helper.c +++ b/src/dhcp-manager/nm-dhcp-helper.c @@ -25,7 +25,7 @@ #include #include -#include +#include "nm-default.h" #define NM_DHCP_CLIENT_DBUS_IFACE "org.freedesktop.nm_dhcp_client" @@ -75,69 +75,6 @@ build_signal_parameters (void) return g_variant_new ("(a{sv})", &builder); } -#if !HAVE_DBUS_GLIB_100 -/* It doesn't matter that nm-dhcp-helper doesn't use dbus-glib itself; the - * workaround code is for if the daemon is built with old dbus-glib. - */ - -static gboolean ever_acquired = FALSE; - -static void -on_name_acquired (GDBusConnection *connection, - const gchar *name, - gpointer user_data) -{ - GMainLoop *loop = user_data; - - ever_acquired = TRUE; - g_main_loop_quit (loop); -} - -static void -on_name_lost (GDBusConnection *connection, - const gchar *name, - gpointer user_data) -{ - if (ever_acquired) { - g_print ("Lost D-Bus name: exiting\n"); - exit (0); - } else { - g_printerr ("Error: Could not acquire the NM DHCP client service.\n"); - exit (1); - } -} - -static GDBusConnection * -shared_connection_init (void) -{ - GDBusConnection *connection; - GError *error = NULL; - GMainLoop *loop; - - connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); - if (!connection) { - g_dbus_error_strip_remote_error (error); - g_printerr ("Error: could not get the system bus. Make sure " - "the message bus daemon is running! Message: %s\n", - error->message); - g_error_free (error); - return NULL; - } - - loop = g_main_loop_new (NULL, FALSE); - g_bus_own_name_on_connection (connection, - "org.freedesktop.nm_dhcp_client", - 0, - on_name_acquired, - on_name_lost, - loop, NULL); - g_main_loop_run (loop); - g_main_loop_unref (loop); - - return connection; -} -#endif - static void fatal_error (void) { @@ -160,24 +97,17 @@ main (int argc, char *argv[]) GDBusConnection *connection; GError *error = NULL; -#if !GLIB_CHECK_VERSION (2, 36, 0) - g_type_init (); -#endif + nm_g_type_init (); connection = g_dbus_connection_new_for_address_sync ("unix:path=" NMRUNDIR "/private-dhcp", G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, NULL, NULL, &error); if (!connection) { -#if !HAVE_DBUS_GLIB_100 - connection = shared_connection_init (); -#endif - if (!connection) { - g_dbus_error_strip_remote_error (error); - g_printerr ("Error: could not connect to NetworkManager D-Bus socket: %s\n", - error->message); - g_error_free (error); - fatal_error (); - } + g_dbus_error_strip_remote_error (error); + g_printerr ("Error: could not connect to NetworkManager D-Bus socket: %s\n", + error->message); + g_error_free (error); + fatal_error (); } if (!g_dbus_connection_emit_signal (connection, diff --git a/src/dhcp-manager/nm-dhcp-helper.conf b/src/dhcp-manager/nm-dhcp-helper.conf deleted file mode 100644 index 0aeae603..00000000 --- a/src/dhcp-manager/nm-dhcp-helper.conf +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - diff --git a/src/dhcp-manager/nm-dhcp-listener.c b/src/dhcp-manager/nm-dhcp-listener.c index ca57ae59..f6fafb80 100644 --- a/src/dhcp-manager/nm-dhcp-listener.c +++ b/src/dhcp-manager/nm-dhcp-listener.c @@ -19,9 +19,6 @@ #include "config.h" -#include -#include -#include #include #include #include @@ -30,12 +27,10 @@ #include #include +#include "nm-default.h" #include "nm-dhcp-listener.h" #include "nm-core-internal.h" -#include "nm-logging.h" -#include "nm-dbus-manager.h" -#include "nm-dbus-glib-types.h" -#include "nm-glib-compat.h" +#include "nm-bus-manager.h" #include "NetworkManagerUtils.h" #define NM_DHCP_CLIENT_DBUS_IFACE "org.freedesktop.nm_dhcp_client" @@ -43,11 +38,10 @@ #define PRIV_SOCK_TAG "dhcp" typedef struct { - NMDBusManager * dbus_mgr; - guint new_conn_id; - guint dis_conn_id; - GHashTable * proxies; - DBusGProxy * proxy; + NMBusManager * dbus_mgr; + gulong new_conn_id; + gulong dis_conn_id; + GHashTable * signal_handlers; } NMDhcpListenerPrivate; #define NM_DHCP_LISTENER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP_LISTENER, NMDhcpListenerPrivate)) @@ -63,61 +57,45 @@ static guint signals[LAST_SIGNAL] = { 0 }; /***************************************************/ static char * -garray_to_string (GArray *array, const char *key) +get_option (GVariant *options, const char *key) { - GString *str; - int i; - unsigned char c; - char *converted = NULL; + GVariant *value; + const guchar *bytes, *s; + gsize len; + char *converted, *d; - g_return_val_if_fail (array != NULL, NULL); + if (!g_variant_lookup (options, key, "@ay", &value)) + return NULL; + + bytes = g_variant_get_fixed_array (value, &len, 1); /* Since the DHCP options come through environment variables, they should * already be UTF-8 safe, but just make sure. */ - str = g_string_sized_new (array->len); - for (i = 0; i < array->len; i++) { - c = array->data[i]; - + converted = g_malloc (len + 1); + for (s = bytes, d = converted; s < bytes + len; s++, d++) { /* Convert NULLs to spaces and non-ASCII characters to ? */ - if (c == '\0') - c = ' '; - else if (c > 127) - c = '?'; - str = g_string_append_c (str, c); + if (*s == '\0') + *d = ' '; + else if (*s > 127) + *d = '?'; + else + *d = *s; } - str = g_string_append_c (str, '\0'); + *d = '\0'; + g_variant_unref (value); - converted = str->str; - if (!g_utf8_validate (converted, -1, NULL)) - nm_log_warn (LOGD_DHCP, "DHCP option '%s' couldn't be converted to UTF-8", key); - g_string_free (str, FALSE); return converted; } -static char * -get_option (GHashTable *hash, const char *key) -{ - GValue *value; - - value = g_hash_table_lookup (hash, key); - if (value == NULL) - return NULL; - - if (G_VALUE_TYPE (value) != DBUS_TYPE_G_UCHAR_ARRAY) { - nm_log_warn (LOGD_DHCP, "unexpected key %s value type was not " - "DBUS_TYPE_G_UCHAR_ARRAY", - (char *) key); - return NULL; - } - - return garray_to_string ((GArray *) g_value_get_boxed (value), key); -} - static void -handle_event (DBusGProxy *proxy, - GHashTable *options, - gpointer user_data) +handle_event (GDBusConnection *connection, + const char *sender_name, + const char *object_path, + const char *interface_name, + const char *signal_name, + GVariant *parameters, + gpointer user_data) { NMDhcpListener *self = NM_DHCP_LISTENER (user_data); char *iface = NULL; @@ -125,6 +103,12 @@ handle_event (DBusGProxy *proxy, char *reason = NULL; gint pid; gboolean handled = FALSE; + GVariant *options; + + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(a{sv})"))) + return; + + g_variant_get (parameters, "(@a{sv})", &options); iface = get_option (options, "interface"); if (iface == NULL) { @@ -158,39 +142,43 @@ out: g_free (iface); g_free (pid_str); g_free (reason); + g_variant_unref (options); } -#if HAVE_DBUS_GLIB_100 static void -new_connection_cb (NMDBusManager *mgr, - DBusGConnection *connection, +new_connection_cb (NMBusManager *mgr, + GDBusConnection *connection, + GDBusObjectManager *manager, NMDhcpListener *self) { - DBusGProxy *proxy; - - /* Create a new proxy for the client */ - proxy = dbus_g_proxy_new_for_peer (connection, "/", NM_DHCP_CLIENT_DBUS_IFACE); - dbus_g_proxy_add_signal (proxy, "Event", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (proxy, "Event", G_CALLBACK (handle_event), self, NULL); - - g_hash_table_insert (NM_DHCP_LISTENER_GET_PRIVATE (self)->proxies, connection, proxy); + NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE (self); + guint id; + + id = g_dbus_connection_signal_subscribe (connection, + NULL, + NM_DHCP_CLIENT_DBUS_IFACE, + "Event", + NULL, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + handle_event, self, NULL); + g_hash_table_insert (priv->signal_handlers, connection, GUINT_TO_POINTER (id)); } static void -dis_connection_cb (NMDBusManager *mgr, - DBusGConnection *connection, +dis_connection_cb (NMBusManager *mgr, + GDBusConnection *connection, NMDhcpListener *self) { NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE (self); - DBusGProxy *proxy; + guint id; - proxy = g_hash_table_lookup (priv->proxies, connection); - if (proxy) { - dbus_g_proxy_disconnect_signal (proxy, "Event", G_CALLBACK (handle_event), self); - g_hash_table_remove (priv->proxies, connection); + id = GPOINTER_TO_UINT (g_hash_table_lookup (priv->signal_handlers, connection)); + if (id) { + g_dbus_connection_signal_unsubscribe (connection, id); + g_hash_table_remove (priv->signal_handlers, connection); } } -#endif /***************************************************/ @@ -200,36 +188,22 @@ static void nm_dhcp_listener_init (NMDhcpListener *self) { NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE (self); -#if !HAVE_DBUS_GLIB_100 - DBusGConnection *g_connection; -#endif - /* Maps DBusGConnection :: DBusGProxy */ - priv->proxies = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); + /* Maps GDBusConnection :: GDBusProxy */ + priv->signal_handlers = g_hash_table_new (NULL, NULL); - priv->dbus_mgr = nm_dbus_manager_get (); + priv->dbus_mgr = nm_bus_manager_get (); -#if HAVE_DBUS_GLIB_100 /* Register the socket our DHCP clients will return lease info on */ - nm_dbus_manager_private_server_register (priv->dbus_mgr, PRIV_SOCK_PATH, PRIV_SOCK_TAG); + nm_bus_manager_private_server_register (priv->dbus_mgr, PRIV_SOCK_PATH, PRIV_SOCK_TAG); priv->new_conn_id = g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW "::" PRIV_SOCK_TAG, + NM_BUS_MANAGER_PRIVATE_CONNECTION_NEW "::" PRIV_SOCK_TAG, G_CALLBACK (new_connection_cb), self); priv->dis_conn_id = g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "::" PRIV_SOCK_TAG, + NM_BUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "::" PRIV_SOCK_TAG, G_CALLBACK (dis_connection_cb), self); -#else - g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr); - priv->proxy = dbus_g_proxy_new_for_name (g_connection, - "org.freedesktop.nm_dhcp_client", - "/", - NM_DHCP_CLIENT_DBUS_IFACE); - g_assert (priv->proxy); - dbus_g_proxy_add_signal (priv->proxy, "Event", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "Event", G_CALLBACK (handle_event), self, NULL); -#endif } static void @@ -237,21 +211,11 @@ dispose (GObject *object) { NMDhcpListenerPrivate *priv = NM_DHCP_LISTENER_GET_PRIVATE (object); - if (priv->new_conn_id) { - g_signal_handler_disconnect (priv->dbus_mgr, priv->new_conn_id); - priv->new_conn_id = 0; - } - if (priv->dis_conn_id) { - g_signal_handler_disconnect (priv->dbus_mgr, priv->dis_conn_id); - priv->dis_conn_id = 0; - } + nm_clear_g_signal_handler (priv->dbus_mgr, &priv->new_conn_id); + nm_clear_g_signal_handler (priv->dbus_mgr, &priv->dis_conn_id); priv->dbus_mgr = NULL; - if (priv->proxies) { - g_hash_table_destroy (priv->proxies); - priv->proxies = NULL; - } - g_clear_object (&priv->proxy); + g_clear_pointer (&priv->signal_handlers, g_hash_table_destroy); G_OBJECT_CLASS (nm_dhcp_listener_parent_class)->dispose (object); } @@ -277,6 +241,6 @@ nm_dhcp_listener_class_init (NMDhcpListenerClass *listener_class) 4, G_TYPE_STRING, /* iface */ G_TYPE_INT, /* pid */ - G_TYPE_HASH_TABLE, /* options */ + G_TYPE_VARIANT, /* options */ G_TYPE_STRING); /* reason */ } diff --git a/src/dhcp-manager/nm-dhcp-listener.h b/src/dhcp-manager/nm-dhcp-listener.h index 15ec0531..b2631acc 100644 --- a/src/dhcp-manager/nm-dhcp-listener.h +++ b/src/dhcp-manager/nm-dhcp-listener.h @@ -19,8 +19,7 @@ #ifndef __NETWORKMANAGER_DHCP_LISTENER_H__ #define __NETWORKMANAGER_DHCP_LISTENER_H__ -#include -#include +#include "nm-default.h" #define NM_TYPE_DHCP_LISTENER (nm_dhcp_listener_get_type ()) #define NM_DHCP_LISTENER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP_LISTENER, NMDhcpListener)) diff --git a/src/dhcp-manager/nm-dhcp-manager.c b/src/dhcp-manager/nm-dhcp-manager.c index af6ec087..cb74a5bc 100644 --- a/src/dhcp-manager/nm-dhcp-manager.c +++ b/src/dhcp-manager/nm-dhcp-manager.c @@ -22,8 +22,6 @@ #include "config.h" -#include -#include #include #include #include @@ -34,14 +32,12 @@ #include #include +#include "nm-default.h" #include "nm-dhcp-manager.h" #include "nm-dhcp-dhclient.h" #include "nm-dhcp-dhcpcd.h" #include "nm-dhcp-systemd.h" -#include "nm-logging.h" #include "nm-config.h" -#include "nm-dbus-glib-types.h" -#include "nm-glib-compat.h" #include "NetworkManagerUtils.h" #define DHCP_TIMEOUT 45 /* default DHCP timeout, in seconds */ @@ -183,7 +179,7 @@ get_client_type (const char *client, GError **error) static void client_state_changed (NMDhcpClient *client, NMDhcpState state, GObject *ip_config, - GHashTable *options, + GVariant *options, const char *event_id, NMDhcpManager *self); @@ -204,7 +200,7 @@ static void client_state_changed (NMDhcpClient *client, NMDhcpState state, GObject *ip_config, - GHashTable *options, + GVariant *options, const char *event_id, NMDhcpManager *self) { @@ -220,10 +216,12 @@ client_start (NMDhcpManager *self, const char *uuid, guint32 priority, gboolean ipv6, + const struct in6_addr *ipv6_ll_addr, const char *dhcp_client_id, guint32 timeout, const char *dhcp_anycast_addr, const char *hostname, + const char *fqdn, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, const char *last_ip4_address) @@ -265,9 +263,9 @@ client_start (NMDhcpManager *self, g_signal_connect (client, NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED, G_CALLBACK (client_state_changed), self); if (ipv6) - success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, hostname, info_only, privacy); + success = nm_dhcp_client_start_ip6 (client, dhcp_anycast_addr, ipv6_ll_addr, hostname, info_only, privacy); else - success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, last_ip4_address); + success = nm_dhcp_client_start_ip4 (client, dhcp_client_id, dhcp_anycast_addr, hostname, fqdn, last_ip4_address); if (!success) { remove_client (self, client); @@ -296,20 +294,24 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self, guint32 priority, gboolean send_hostname, const char *dhcp_hostname, + const char *dhcp_fqdn, const char *dhcp_client_id, guint32 timeout, const char *dhcp_anycast_addr, const char *last_ip_address) { const char *hostname = NULL; + const char *fqdn = NULL; g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL); - if (send_hostname) + if (send_hostname) { hostname = get_send_hostname (self, dhcp_hostname); - return client_start (self, iface, ifindex, hwaddr, uuid, priority, FALSE, + fqdn = dhcp_fqdn; + } + return client_start (self, iface, ifindex, hwaddr, uuid, priority, FALSE, NULL, dhcp_client_id, timeout, dhcp_anycast_addr, hostname, - FALSE, 0, last_ip_address); + fqdn, FALSE, 0, last_ip_address); } /* Caller owns a reference to the NMDhcpClient on return */ @@ -318,6 +320,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, const char *iface, int ifindex, const GByteArray *hwaddr, + const struct in6_addr *ll_addr, const char *uuid, guint32 priority, gboolean send_hostname, @@ -334,7 +337,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self, if (send_hostname) hostname = get_send_hostname (self, dhcp_hostname); return client_start (self, iface, ifindex, hwaddr, uuid, priority, TRUE, - NULL, timeout, dhcp_anycast_addr, hostname, info_only, + ll_addr, NULL, timeout, dhcp_anycast_addr, hostname, NULL, info_only, privacy, NULL); } @@ -355,6 +358,7 @@ nm_dhcp_manager_set_default_hostname (NMDhcpManager *manager, const char *hostna GSList * nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self, const char *iface, + int ifindex, const char *uuid, gboolean ipv6, guint32 default_route_metric) @@ -363,11 +367,12 @@ nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self, g_return_val_if_fail (NM_IS_DHCP_MANAGER (self), NULL); g_return_val_if_fail (iface != NULL, NULL); + g_return_val_if_fail (ifindex >= -1, NULL); g_return_val_if_fail (uuid != NULL, NULL); desc = find_client_desc (NULL, NM_DHCP_MANAGER_GET_PRIVATE (self)->client_type); if (desc && desc->get_lease_configs_func) - return desc->get_lease_configs_func (iface, uuid, ipv6, default_route_metric); + return desc->get_lease_configs_func (iface, ifindex, uuid, ipv6, default_route_metric); return NULL; } diff --git a/src/dhcp-manager/nm-dhcp-manager.h b/src/dhcp-manager/nm-dhcp-manager.h index bf6cc778..42d968ab 100644 --- a/src/dhcp-manager/nm-dhcp-manager.h +++ b/src/dhcp-manager/nm-dhcp-manager.h @@ -22,9 +22,8 @@ #ifndef __NETWORKMANAGER_DHCP_MANAGER_H__ #define __NETWORKMANAGER_DHCP_MANAGER_H__ -#include -#include +#include "nm-default.h" #include "nm-dhcp-client.h" #include "nm-ip4-config.h" #include "nm-dhcp4-config.h" @@ -59,6 +58,7 @@ NMDhcpClient * nm_dhcp_manager_start_ip4 (NMDhcpManager *manager, guint32 priority, gboolean send_hostname, const char *dhcp_hostname, + const char *dhcp_fqdn, const char *dhcp_client_id, guint32 timeout, const char *dhcp_anycast_addr, @@ -68,6 +68,7 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, const char *iface, int ifindex, const GByteArray *hwaddr, + const struct in6_addr *ll_addr, const char *uuid, guint32 priority, gboolean send_hostname, @@ -79,6 +80,7 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager, GSList * nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self, const char *iface, + int ifindex, const char *uuid, gboolean ipv6, guint32 default_route_metric); diff --git a/src/dhcp-manager/nm-dhcp-systemd.c b/src/dhcp-manager/nm-dhcp-systemd.c index 571765f7..4f68a0b6 100644 --- a/src/dhcp-manager/nm-dhcp-systemd.c +++ b/src/dhcp-manager/nm-dhcp-systemd.c @@ -18,9 +18,6 @@ #include "config.h" -#include -#include -#include #include #include #include @@ -31,16 +28,13 @@ #include #include +#include "nm-default.h" #include "nm-dhcp-systemd.h" #include "nm-utils.h" -#include "nm-logging.h" #include "nm-dhcp-utils.h" #include "NetworkManagerUtils.h" -#include "gsystem-local-alloc.h" #include "nm-platform.h" -#include "nm-sd-adapt.h" - #include "sd-dhcp-client.h" #include "sd-dhcp6-client.h" #include "dhcp-protocol.h" @@ -206,7 +200,9 @@ G_STMT_START { \ } G_STMT_END static NMIP4Config * -lease_to_ip4_config (sd_dhcp_lease *lease, +lease_to_ip4_config (const char *iface, + int ifindex, + sd_dhcp_lease *lease, GHashTable *options, guint32 default_priority, gboolean log_lease, @@ -224,17 +220,19 @@ lease_to_ip4_config (sd_dhcp_lease *lease, guint16 mtu; int r, num; guint64 end_time; - uint8_t *data; + const void *data; + gsize data_len; gboolean metered = FALSE; g_return_val_if_fail (lease != NULL, NULL); - ip4_config = nm_ip4_config_new (); + ip4_config = nm_ip4_config_new (ifindex); /* Address */ sd_dhcp_lease_get_address (lease, &tmp_addr); memset (&address, 0, sizeof (address)); address.address = tmp_addr.s_addr; + address.peer_address = tmp_addr.s_addr; str = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL); LOG_LEASE (LOGD_DHCP4, " address %s", str); add_option (options, dhcp4_requests, DHCP_OPTION_IP_ADDRESS, str); @@ -357,9 +355,9 @@ lease_to_ip4_config (sd_dhcp_lease *lease, g_string_free (l, TRUE); } - num = sd_dhcp_lease_get_vendor_specific (lease, &data); - if (num > 0) - metered = !!memmem (data, num, "ANDROID_METERED", STRLEN ("ANDROID_METERED")); + r = sd_dhcp_lease_get_vendor_specific (lease, &data, &data_len); + if (r >= 0) + metered = !!memmem (data, data_len, "ANDROID_METERED", STRLEN ("ANDROID_METERED")); nm_ip4_config_set_metered (ip4_config, metered); return ip4_config; @@ -378,6 +376,7 @@ get_leasefile_path (const char *iface, const char *uuid, gboolean ipv6) static GSList * nm_dhcp_systemd_get_lease_ip_configs (const char *iface, + int ifindex, const char *uuid, gboolean ipv6, guint32 default_route_metric) @@ -392,9 +391,9 @@ nm_dhcp_systemd_get_lease_ip_configs (const char *iface, return NULL; path = get_leasefile_path (iface, uuid, FALSE); - r = sd_dhcp_lease_load (&lease, path); + r = dhcp_lease_load (&lease, path); if (r == 0 && lease) { - ip4_config = lease_to_ip4_config (lease, NULL, default_route_metric, FALSE, NULL); + ip4_config = lease_to_ip4_config (iface, ifindex, lease, NULL, default_route_metric, FALSE, NULL); if (ip4_config) leases = g_slist_append (leases, ip4_config); sd_dhcp_lease_unref (lease); @@ -448,7 +447,9 @@ bound4_handle (NMDhcpSystemd *self) } options = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); - ip4_config = lease_to_ip4_config (lease, + ip4_config = lease_to_ip4_config (iface, + nm_dhcp_client_get_ifindex (NM_DHCP_CLIENT (self)), + lease, options, nm_dhcp_client_get_priority (NM_DHCP_CLIENT (self)), TRUE, @@ -459,7 +460,7 @@ bound4_handle (NMDhcpSystemd *self) uint8_t type = 0; add_requests_to_options (options, dhcp4_requests); - sd_dhcp_lease_save (lease, priv->lease_file); + dhcp_lease_save (lease, priv->lease_file); sd_dhcp_client_get_client_id(priv->client4, &type, &client_id, &client_id_len); if (client_id) @@ -475,7 +476,6 @@ bound4_handle (NMDhcpSystemd *self) g_clear_error (&error); } - sd_dhcp_lease_unref (lease); g_hash_table_destroy (options); g_clear_object (&ip4_config); } @@ -492,15 +492,15 @@ dhcp_event_cb (sd_dhcp_client *client, int event, gpointer user_data) nm_log_dbg (LOGD_DHCP4, "(%s): DHCPv4 client event %d", iface, event); switch (event) { - case DHCP_EVENT_EXPIRED: + case SD_DHCP_CLIENT_EVENT_EXPIRED: nm_dhcp_client_set_state (NM_DHCP_CLIENT (user_data), NM_DHCP_STATE_EXPIRE, NULL, NULL); break; - case DHCP_EVENT_STOP: + case SD_DHCP_CLIENT_EVENT_STOP: nm_dhcp_client_set_state (NM_DHCP_CLIENT (user_data), NM_DHCP_STATE_FAIL, NULL, NULL); break; - case DHCP_EVENT_RENEW: - case DHCP_EVENT_IP_CHANGE: - case DHCP_EVENT_IP_ACQUIRE: + case SD_DHCP_CLIENT_EVENT_RENEW: + case SD_DHCP_CLIENT_EVENT_IP_CHANGE: + case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE: bound4_handle (self); break; default: @@ -531,7 +531,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last const uint8_t *client_id = NULL; size_t client_id_len = 0; struct in_addr last_addr = { 0 }; - const char *hostname; + const char *hostname, *fqdn; int r, i; gboolean success = FALSE; @@ -583,7 +583,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last goto error; } - sd_dhcp_lease_load (&lease, priv->lease_file); + dhcp_lease_load (&lease, priv->lease_file); if (last_ip4_address) inet_pton (AF_INET, last_ip4_address, &last_addr); @@ -607,7 +607,7 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last client_id + 1, client_id_len - 1); } else if (lease) { - r = sd_dhcp_lease_get_client_id (lease, &client_id, &client_id_len); + r = sd_dhcp_lease_get_client_id (lease, (const void **) &client_id, &client_id_len); if (r == 0 && client_id_len) { sd_dhcp_client_set_client_id (priv->client4, client_id[0], @@ -629,13 +629,32 @@ ip4_start (NMDhcpClient *client, const char *dhcp_anycast_addr, const char *last hostname = nm_dhcp_client_get_hostname (client); if (hostname) { - r = sd_dhcp_client_set_hostname (priv->client4, hostname); + char *prefix, *dot; + + prefix = strdup (hostname); + dot = strchr (prefix, '.'); + /* get rid of the domain */ + if (dot) + *dot = '\0'; + + r = sd_dhcp_client_set_hostname (priv->client4, prefix); + free (prefix); + if (r < 0) { nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP hostname (%d)", iface, r); goto error; } } + fqdn = nm_dhcp_client_get_fqdn (client); + if (fqdn) { + r = sd_dhcp_client_set_hostname (priv->client4, fqdn); + if (r < 0) { + nm_log_warn (LOGD_DHCP4, "(%s): failed to set DHCP FQDN (%d)", iface, r); + goto error; + } + } + r = sd_dhcp_client_start (priv->client4); if (r < 0) { nm_log_warn (LOGD_DHCP4, "(%s): failed to start DHCP (%d)", iface, r); @@ -672,14 +691,14 @@ dhcp6_event_cb (sd_dhcp6_client *client, int event, gpointer user_data) nm_log_dbg (LOGD_DHCP6, "(%s): DHCPv6 client event %d", iface, event); switch (event) { - case DHCP6_EVENT_RETRANS_MAX: + case SD_DHCP6_CLIENT_EVENT_RETRANS_MAX: nm_dhcp_client_set_state (NM_DHCP_CLIENT (user_data), NM_DHCP_STATE_TIMEOUT, NULL, NULL); break; - case DHCP6_EVENT_RESEND_EXPIRE: - case DHCP6_EVENT_STOP: + case SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE: + case SD_DHCP6_CLIENT_EVENT_STOP: nm_dhcp_client_set_state (NM_DHCP_CLIENT (user_data), NM_DHCP_STATE_FAIL, NULL, NULL); break; - case DHCP6_EVENT_IP_ACQUIRE: + case SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE: bound6_handle (self); break; default: @@ -691,6 +710,7 @@ dhcp6_event_cb (sd_dhcp6_client *client, int event, gpointer user_data) static gboolean ip6_start (NMDhcpClient *client, const char *dhcp_anycast_addr, + const struct in6_addr *ll_addr, gboolean info_only, NMSettingIP6ConfigPrivacy privacy, const GByteArray *duid) @@ -749,12 +769,6 @@ ip6_start (NMDhcpClient *client, goto error; } - r = sd_dhcp6_client_set_ifname (priv->client6, iface); - if (r < 0) { - nm_log_warn (LOGD_DHCP6, "(%s): failed to set DHCP ifname (%d)", iface, r); - goto error; - } - r = sd_dhcp6_client_set_callback (priv->client6, dhcp6_event_cb, client); if (r < 0) { nm_log_warn (LOGD_DHCP6, "(%s): failed to set DHCP callback (%d)", iface, r); @@ -767,6 +781,12 @@ ip6_start (NMDhcpClient *client, sd_dhcp6_client_set_request_option (priv->client6, dhcp6_requests[i].num); } + r = sd_dhcp6_client_set_local_address (priv->client6, ll_addr); + if (r < 0) { + nm_log_warn (LOGD_DHCP6, "(%s): failed to set local address (%d)", iface, r); + goto error; + } + r = sd_dhcp6_client_start (priv->client6); if (r < 0) { nm_log_warn (LOGD_DHCP6, "(%s): failed to start DHCP (%d)", iface, r); @@ -848,7 +868,7 @@ nm_dhcp_systemd_class_init (NMDhcpSystemdClass *sdhcp_class) static void __attribute__((constructor)) register_dhcp_dhclient (void) { - g_type_init (); + nm_g_type_init (); _nm_dhcp_client_register (NM_TYPE_DHCP_SYSTEMD, "internal", NULL, diff --git a/src/dhcp-manager/nm-dhcp-systemd.h b/src/dhcp-manager/nm-dhcp-systemd.h index 2a7a463e..ff24bfcd 100644 --- a/src/dhcp-manager/nm-dhcp-systemd.h +++ b/src/dhcp-manager/nm-dhcp-systemd.h @@ -19,9 +19,6 @@ #ifndef NM_DHCP_SYSTEMD_H #define NM_DHCP_SYSTEMD_H -#include -#include - #include "nm-dhcp-client.h" #define NM_TYPE_DHCP_SYSTEMD (nm_dhcp_systemd_get_type ()) diff --git a/src/dhcp-manager/nm-dhcp-utils.c b/src/dhcp-manager/nm-dhcp-utils.c index 75809422..591a0d1f 100644 --- a/src/dhcp-manager/nm-dhcp-utils.c +++ b/src/dhcp-manager/nm-dhcp-utils.c @@ -19,13 +19,12 @@ #include "config.h" -#include #include #include #include #include -#include "nm-logging.h" +#include "nm-default.h" #include "nm-dhcp-utils.h" #include "nm-utils.h" #include "NetworkManagerUtils.h" @@ -321,7 +320,7 @@ process_classful_routes (GHashTable *options, guint32 priority, NMIP4Config *ip4 nm_ip4_config_add_route (ip4_config, &route); nm_log_info (LOGD_DHCP, " static route %s", - nm_platform_ip4_route_to_string (&route)); + nm_platform_ip4_route_to_string (&route, NULL, 0)); } out: @@ -374,27 +373,28 @@ ip4_add_domain_search (gpointer data, gpointer user_data) } NMIP4Config * -nm_dhcp_utils_ip4_config_from_options (const char *iface, +nm_dhcp_utils_ip4_config_from_options (int ifindex, + const char *iface, GHashTable *options, guint32 priority) { NMIP4Config *ip4_config = NULL; guint32 tmp_addr; + in_addr_t addr; NMPlatformIP4Address address; char *str = NULL; guint32 gwaddr = 0, plen = 0; g_return_val_if_fail (options != NULL, NULL); - ip4_config = nm_ip4_config_new (); + ip4_config = nm_ip4_config_new (ifindex); memset (&address, 0, sizeof (address)); address.timestamp = nm_utils_get_monotonic_timestamp_s (); str = g_hash_table_lookup (options, "ip_address"); - if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) { - address.address = tmp_addr; + if (str && (inet_pton (AF_INET, str, &addr) > 0)) nm_log_info (LOGD_DHCP4, " address %s", str); - } else + else goto error; str = g_hash_table_lookup (options, "subnet_mask"); @@ -403,10 +403,10 @@ nm_dhcp_utils_ip4_config_from_options (const char *iface, nm_log_info (LOGD_DHCP4, " plen %d (%s)", plen, str); } else { /* Get default netmask for the IP according to appropriate class. */ - plen = nm_utils_ip4_get_default_prefix (address.address); + plen = nm_utils_ip4_get_default_prefix (addr); nm_log_info (LOGD_DHCP4, " plen %d (default)", plen); } - address.plen = plen; + nm_platform_ip4_address_set_addr (&address, addr, plen); /* Routes: if the server returns classless static routes, we MUST ignore * the 'static_routes' option. @@ -469,7 +469,7 @@ nm_dhcp_utils_ip4_config_from_options (const char *iface, route.metric = priority; nm_ip4_config_add_route (ip4_config, &route); nm_log_dbg (LOGD_IP, "adding route for server identifier: %s", - nm_platform_ip4_route_to_string (&route)); + nm_platform_ip4_route_to_string (&route, NULL, 0)); } } else @@ -594,7 +594,8 @@ ip6_add_domain_search (gpointer data, gpointer user_data) } NMIP6Config * -nm_dhcp_utils_ip6_config_from_options (const char *iface, +nm_dhcp_utils_ip6_config_from_options (int ifindex, + const char *iface, GHashTable *options, guint32 priority, gboolean info_only) @@ -618,7 +619,7 @@ nm_dhcp_utils_ip6_config_from_options (const char *iface, iface, (const char *) key, (const char *) value); } - ip6_config = nm_ip6_config_new (); + ip6_config = nm_ip6_config_new (ifindex); str = g_hash_table_lookup (options, "max_life"); if (str) { diff --git a/src/dhcp-manager/nm-dhcp-utils.h b/src/dhcp-manager/nm-dhcp-utils.h index a01cf4c2..056982c3 100644 --- a/src/dhcp-manager/nm-dhcp-utils.h +++ b/src/dhcp-manager/nm-dhcp-utils.h @@ -20,15 +20,19 @@ #define __NETWORKMANAGER_DHCP_UTILS_H__ #include -#include + #include #include -NMIP4Config *nm_dhcp_utils_ip4_config_from_options (const char *iface, +#include "nm-default.h" + +NMIP4Config *nm_dhcp_utils_ip4_config_from_options (int ifindex, + const char *iface, GHashTable *options, guint priority); -NMIP6Config *nm_dhcp_utils_ip6_config_from_options (const char *iface, +NMIP6Config *nm_dhcp_utils_ip6_config_from_options (int ifindex, + const char *iface, GHashTable *options, guint priority, gboolean info_only); diff --git a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c deleted file mode 100644 index 3870342c..00000000 --- a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.c +++ /dev/null @@ -1,236 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* 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) 2014 Red Hat, Inc. - */ - -#include "config.h" - -#include -#include -#include - -#include "sd-event.h" -#include "time-util.h" - -struct sd_event_source { - guint refcount; - guint id; - gpointer user_data; - - GIOChannel *channel; - - union { - struct { - sd_event_io_handler_t cb; - } io; - struct { - sd_event_time_handler_t cb; - uint64_t usec; - } time; - }; -}; - -static struct sd_event_source * -source_new (void) -{ - struct sd_event_source *source; - - source = g_slice_new0 (struct sd_event_source); - source->refcount = 1; - return source; -} - -int -sd_event_source_set_priority (sd_event_source *s, int64_t priority) -{ - return 0; -} - -sd_event_source* -sd_event_source_unref (sd_event_source *s) -{ - - if (!s) - return NULL; - - g_return_val_if_fail (s->refcount, NULL); - - s->refcount--; - if (s->refcount == 0) { - if (s->id) - g_source_remove (s->id); - if (s->channel) { - /* Don't shut down the channel since systemd will soon close - * the file descriptor itself, which would cause -EBADF. - */ - g_io_channel_unref (s->channel); - } - g_slice_free (struct sd_event_source, s); - } - return NULL; -} - -int -sd_event_source_set_description(sd_event_source *s, const char *description) -{ - if (!s) - return -EINVAL; - - g_source_set_name_by_id (s->id, description); - return 0; -} - -static gboolean -io_ready (GIOChannel *channel, GIOCondition condition, struct sd_event_source *source) -{ - int r, revents = 0; - gboolean result; - - if (condition & G_IO_IN) - revents |= EPOLLIN; - if (condition & G_IO_OUT) - revents |= EPOLLOUT; - if (condition & G_IO_PRI) - revents |= EPOLLPRI; - if (condition & G_IO_ERR) - revents |= EPOLLERR; - if (condition & G_IO_HUP) - revents |= EPOLLHUP; - - source->refcount++; - - r = source->io.cb (source, g_io_channel_unix_get_fd (channel), revents, source->user_data); - if (r < 0 || source->refcount <= 1) { - source->id = 0; - result = G_SOURCE_REMOVE; - } else - result = G_SOURCE_CONTINUE; - - sd_event_source_unref (source); - - return result; -} - -int -sd_event_add_io (sd_event *e, sd_event_source **s, int fd, uint32_t events, sd_event_io_handler_t callback, void *userdata) -{ - struct sd_event_source *source; - GIOChannel *channel; - GIOCondition condition = 0; - - /* systemd supports floating sd_event_source by omitting the @s argument. - * We don't have such users and don't implement floating references. */ - g_return_val_if_fail (s, -EINVAL); - - channel = g_io_channel_unix_new (fd); - if (!channel) - return -EINVAL; - - source = source_new (); - source->io.cb = callback; - source->user_data = userdata; - source->channel = channel; - - if (events & EPOLLIN) - condition |= G_IO_IN; - if (events & EPOLLOUT) - condition |= G_IO_OUT; - if (events & EPOLLPRI) - condition |= G_IO_PRI; - if (events & EPOLLERR) - condition |= G_IO_ERR; - if (events & EPOLLHUP) - condition |= G_IO_HUP; - - g_io_channel_set_encoding (source->channel, NULL, NULL); - g_io_channel_set_buffered (source->channel, FALSE); - source->id = g_io_add_watch (source->channel, condition, (GIOFunc) io_ready, source); - - *s = source; - return 0; -} - -static gboolean -time_ready (struct sd_event_source *source) -{ - source->refcount++; - - source->time.cb (source, source->time.usec, source->user_data); - source->id = 0; - - sd_event_source_unref (source); - - return G_SOURCE_REMOVE; -} - -int -sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata) -{ - struct sd_event_source *source; - uint64_t n = now (clock); - - /* systemd supports floating sd_event_source by omitting the @s argument. - * We don't have such users and don't implement floating references. */ - g_return_val_if_fail (s, -EINVAL); - - source = source_new (); - source->time.cb = callback; - source->user_data = userdata; - source->time.usec = usec; - - if (usec > 1000) - usec = n < usec - 1000 ? usec - n : 1000; - source->id = g_timeout_add (usec / 1000, (GSourceFunc) time_ready, source); - - *s = source; - return 0; -} - -/* sd_event is basically a GMainContext; but since we only - * ever use the default context, nothing to do here. - */ - -int -sd_event_default (sd_event **e) -{ - *e = GUINT_TO_POINTER (1); - return 0; -} - -sd_event* -sd_event_ref (sd_event *e) -{ - return e; -} - -sd_event* -sd_event_unref (sd_event *e) -{ - return NULL; -} - -int -sd_event_now (sd_event *e, clockid_t clock, uint64_t *usec) -{ - *usec = now (clock); - return 0; -} - -int asynchronous_close(int fd) { - safe_close(fd); - return -1; -} - diff --git a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h b/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h deleted file mode 100644 index 5e91c307..00000000 --- a/src/dhcp-manager/systemd-dhcp/nm-sd-adapt.h +++ /dev/null @@ -1,132 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* 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) 2014 Red Hat, Inc. - */ - -#ifndef NM_SD_ADAPT_H -#define NM_SD_ADAPT_H - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_AUXV_H -#include -#endif -#include -#include -#include - -#include "nm-logging.h" - -/* Missing in Linux 3.2.0, in Ubuntu 12.04 */ -#ifndef BPF_XOR -#define BPF_XOR 0xa0 -#endif - -#ifndef CLOCK_BOOTTIME -#define CLOCK_BOOTTIME 7 -#endif - -/*****************************************************************************/ - -static inline guint32 -_slog_level_to_nm (int slevel) -{ - switch (slevel) { - case LOG_DEBUG: return LOGL_DEBUG; - case LOG_WARNING: return LOGL_WARN; - case LOG_ERR: return LOGL_ERR; - case LOG_INFO: - case LOG_NOTICE: - default: return LOGL_INFO; - } -} - -#define log_meta(level, file, line, func, format, ...) \ -G_STMT_START { \ - guint32 _l = _slog_level_to_nm ((level)); \ - if (nm_logging_enabled (_l, LOGD_DHCP)) { \ - const char *_location = strrchr (file "", '/'); \ - \ - _nm_log_impl (_location ? _location + 1 : file, line, func, _l, LOGD_DHCP, 0, format, ## __VA_ARGS__); \ - } \ -} G_STMT_END - -#define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__) -#define log_error(...) log_full(LOG_ERR, __VA_ARGS__) -#define log_full(level, ...) log_meta((level), __FILE__, __LINE__, __func__, __VA_ARGS__); - -#define log_dhcp_client(client, fmt, ...) \ - log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__) - -#define log_assert_failed(e, file, line, func) \ -G_STMT_START { \ - nm_log_err (LOGD_DHCP, "%s:%d (%s): assertion failed: %s", (""file), (line), (func), G_STRINGIFY (e)); \ - g_assert (FALSE); \ -} G_STMT_END - -#define log_assert_failed_unreachable(t, file, line, func) \ -G_STMT_START { \ - nm_log_err (LOGD_DHCP, "%s:%d (%s): assert unreachable: %s", (""file), (line), (func), G_STRINGIFY (t)); \ - g_assert_not_reached (); \ -} G_STMT_END - -#define log_assert_failed_return(e, file, line, func) \ -G_STMT_START { \ - nm_log_err (LOGD_DHCP, "%s:%d (%s): assert return: %s", (""file), (line), (func), G_STRINGIFY (e)); \ -} G_STMT_END - -#define log_oom nm_log_err(LOGD_CORE, "%s:%s/%s: OOM", __FILE__, __LINE__, __func__) - -/* Can't include both net/if.h and linux/if.h; so have to define this here */ -#ifndef IFNAMSIZ -#define IFNAMSIZ 16 -#endif - -#ifndef MAX_HANDLE_SZ -#define MAX_HANDLE_SZ 128 -#endif - -#define noreturn G_GNUC_NORETURN - -/* - * Some toolchains (E.G. uClibc 0.9.33 and earlier) don't export - * CLOCK_BOOTTIME even though the kernel supports it, so provide a - * local definition - */ -#ifndef CLOCK_BOOTTIME -#define CLOCK_BOOTTIME 7 -#endif - -#include "sd-id128.h" -#include "sparse-endian.h" -#include "async.h" -#include "util.h" - -static inline pid_t gettid(void) { - return (pid_t) syscall(SYS_gettid); -} - -#endif /* NM_SD_ADAPT_H */ - diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-internal.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-internal.h deleted file mode 100644 index 28c0e634..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-internal.h +++ /dev/null @@ -1,76 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. - Copyright (C) 2014 Tom Gundersen - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "nm-sd-adapt.h" - -#include -#include -#include -#include - -#include "socket-util.h" - -#include "sd-dhcp-client.h" -#include "dhcp-protocol.h" - -int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, - uint32_t xid, const uint8_t *mac_addr, - size_t mac_addr_len, uint16_t arp_type); -int dhcp_network_bind_udp_socket(be32_t address, uint16_t port); -int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, - const void *packet, size_t len); -int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, - const void *packet, size_t len); - -int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_t overload, - uint8_t code, size_t optlen, const void *optval); - -typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len, - const uint8_t *option, void *user_data); - -int dhcp_option_parse(DHCPMessage *message, size_t len, - dhcp_option_cb_t cb, void *user_data); - -int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, - uint8_t type, uint16_t arp_type, size_t optlen, - size_t *optoffset); - -uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len); - -void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr, - uint16_t source, be32_t destination_addr, - uint16_t destination, uint16_t len); - -int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum); - -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref); -#define _cleanup_dhcp_client_unref_ _cleanup_(sd_dhcp_client_unrefp) - -/* If we are invoking callbacks of a dhcp-client, ensure unreffing the - * client from the callback doesn't destroy the object we are working - * on */ -#define DHCP_CLIENT_DONT_DESTROY(client) \ - _cleanup_dhcp_client_unref_ _unused_ sd_dhcp_client *_dont_destroy_##client = sd_dhcp_client_ref(client) - -#define log_dhcp_client(client, fmt, ...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__) diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h deleted file mode 100644 index 71f7f143..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-lease-internal.h +++ /dev/null @@ -1,89 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. - Copyright (C) 2014 Tom Gundersen - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "refcnt.h" -#include "util.h" - -#include "dhcp-protocol.h" - -#include "sd-dhcp-client.h" - -struct sd_dhcp_route { - struct in_addr dst_addr; - struct in_addr gw_addr; - unsigned char dst_prefixlen; -}; - -struct sd_dhcp_lease { - RefCount n_ref; - - int32_t time_offset; - uint32_t t1; - uint32_t t2; - uint32_t lifetime; - uint32_t mtu_aging_timeout; - be32_t address; - be32_t server_address; - be32_t subnet_mask; - be32_t router; - be32_t next_server; - be32_t broadcast; - struct in_addr *dns; - size_t dns_size; - struct in_addr *ntp; - size_t ntp_size; - struct in_addr *policy_filter; - size_t policy_filter_size; - struct sd_dhcp_route *static_route; - size_t static_route_size; - size_t static_route_allocated; - uint16_t boot_file_size; - uint16_t mdr; - uint16_t mtu; - uint8_t ttl; - bool ip_forward; - bool ip_forward_non_local; - char *domainname; - char *hostname; - char *root_path; - uint8_t *client_id; - size_t client_id_len; - uint8_t *vendor_specific; - size_t vendor_specific_size; -}; - -int dhcp_lease_new(sd_dhcp_lease **ret); -int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option, - void *user_data); - -int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease); - -int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id, - size_t client_id_len); - -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_lease*, sd_dhcp_lease_unref); -#define _cleanup_dhcp_lease_unref_ _cleanup_(sd_dhcp_lease_unrefp) diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c deleted file mode 100644 index 971b3aa1..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-network.c +++ /dev/null @@ -1,241 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "config.h" - -#include "nm-sd-adapt.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "socket-util.h" - -#include "dhcp-internal.h" - -static int _bind_raw_socket(int ifindex, union sockaddr_union *link, - uint32_t xid, const uint8_t *mac_addr, - size_t mac_addr_len, - const uint8_t *bcast_addr, - const struct ether_addr *eth_mac, - uint16_t arp_type, uint8_t dhcp_hlen) { - struct sock_filter filter[] = { - BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ - BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(DHCPPacket), 1, 0), /* packet >= DHCPPacket ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, ip.protocol)), /* A <- IP protocol */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0), /* IP protocol == UDP ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, ip.frag_off)), /* A <- Flags */ - BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x20), /* A <- A & 0x20 (More Fragments bit) */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, ip.frag_off)), /* A <- Flags + Fragment offset */ - BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x1fff), /* A <- A & 0x1fff (Fragment offset) */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, udp.dest)), /* A <- UDP destination port */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_PORT_CLIENT, 1, 0), /* UDP destination port == DHCP client port ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.op)), /* A <- DHCP op */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTREPLY, 1, 0), /* op == BOOTREPLY ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.htype)), /* A <- DHCP header type */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arp_type, 1, 0), /* header type == arp_type ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- mac address length */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0), /* address length == dhcp_hlen ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)), /* A <- client identifier */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0), /* client identifier == xid ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_IMM, htobe32(*((unsigned int *) eth_mac))), /* A <- 4 bytes of client's MAC */ - BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */ - BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_IMM, htobe16(*((unsigned short *) (((char *) eth_mac) + 4)))), /* A <- remainder of client's MAC */ - BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4), /* A <- remainder of MAC from dhcp.chaddr */ - BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)), /* A <- DHCP magic cookie */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0), /* cookie == DHCP magic cookie ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */ - }; - struct sock_fprog fprog = { - .len = ELEMENTSOF(filter), - .filter = filter - }; - _cleanup_close_ int s = -1; - int r, on = 1; - - assert(ifindex > 0); - assert(link); - - s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); - if (s < 0) - return -errno; - - r = setsockopt(s, SOL_PACKET, PACKET_AUXDATA, &on, sizeof(on)); - if (r < 0) - return -errno; - - r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); - if (r < 0) - return -errno; - - link->ll.sll_family = AF_PACKET; - link->ll.sll_protocol = htons(ETH_P_IP); - link->ll.sll_ifindex = ifindex; - link->ll.sll_hatype = htons(arp_type); - link->ll.sll_halen = mac_addr_len; - memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len); - - r = bind(s, &link->sa, sizeof(link->ll)); - if (r < 0) - return -errno; - - r = s; - s = -1; - - return r; -} - -int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, - uint32_t xid, const uint8_t *mac_addr, - size_t mac_addr_len, uint16_t arp_type) { - static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - /* Default broadcast address for IPoIB */ - static const uint8_t ib_bcast[] = { - 0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff - }; - struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } }; - const uint8_t *bcast_addr = NULL; - uint8_t dhcp_hlen = 0; - - assert_return(mac_addr_len > 0, -EINVAL); - - if (arp_type == ARPHRD_ETHER) { - assert_return(mac_addr_len == ETH_ALEN, -EINVAL); - memcpy(ð_mac, mac_addr, ETH_ALEN); - bcast_addr = eth_bcast; - dhcp_hlen = ETH_ALEN; - } else if (arp_type == ARPHRD_INFINIBAND) { - assert_return(mac_addr_len == INFINIBAND_ALEN, -EINVAL); - bcast_addr = ib_bcast; - } else - return -EINVAL; - - return _bind_raw_socket(ifindex, link, xid, mac_addr, mac_addr_len, - bcast_addr, ð_mac, arp_type, dhcp_hlen); -} - -int dhcp_network_bind_udp_socket(be32_t address, uint16_t port) { - union sockaddr_union src = { - .in.sin_family = AF_INET, - .in.sin_port = htobe16(port), - .in.sin_addr.s_addr = address, - }; - _cleanup_close_ int s = -1; - int r, on = 1, tos = IPTOS_CLASS_CS6; - - s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); - if (s < 0) - return -errno; - - r = setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); - if (r < 0) - return -errno; - - r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - if (r < 0) - return -errno; - - if (address == INADDR_ANY) { - r = setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)); - if (r < 0) - return -errno; - - r = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); - if (r < 0) - return -errno; - } else { - r = setsockopt(s, IPPROTO_IP, IP_FREEBIND, &on, sizeof(on)); - if (r < 0) - return -errno; - } - - r = bind(s, &src.sa, sizeof(src.in)); - if (r < 0) - return -errno; - - r = s; - s = -1; - - return r; -} - -int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, - const void *packet, size_t len) { - int r; - - assert(link); - assert(packet); - assert(len); - - r = sendto(s, packet, len, 0, &link->sa, sizeof(link->ll)); - if (r < 0) - return -errno; - - return 0; -} - -int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, - const void *packet, size_t len) { - union sockaddr_union dest = { - .in.sin_family = AF_INET, - .in.sin_port = htobe16(port), - .in.sin_addr.s_addr = address, - }; - int r; - - assert(s >= 0); - assert(packet); - assert(len); - - r = sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in)); - if (r < 0) - return -errno; - - return 0; -} diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-option.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-option.c deleted file mode 100644 index 9759e575..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-option.c +++ /dev/null @@ -1,257 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "config.h" - -#include "nm-sd-adapt.h" - -#include -#include -#include -#include - -#include "dhcp-internal.h" - -static int option_append(uint8_t options[], size_t size, size_t *offset, - uint8_t code, size_t optlen, const void *optval) { - assert(options); - assert(offset); - - if (code != DHCP_OPTION_END) - /* always make sure there is space for an END option */ - size --; - - switch (code) { - - case DHCP_OPTION_PAD: - case DHCP_OPTION_END: - if (size < *offset + 1) - return -ENOBUFS; - - options[*offset] = code; - *offset += 1; - break; - - default: - if (size < *offset + optlen + 2) - return -ENOBUFS; - - options[*offset] = code; - options[*offset + 1] = optlen; - - if (optlen) { - assert(optval); - - memcpy(&options[*offset + 2], optval, optlen); - } - - *offset += optlen + 2; - - break; - } - - return 0; -} - -int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, - uint8_t overload, - uint8_t code, size_t optlen, const void *optval) { - size_t file_offset = 0, sname_offset =0; - bool file, sname; - int r; - - assert(message); - assert(offset); - - file = overload & DHCP_OVERLOAD_FILE; - sname = overload & DHCP_OVERLOAD_SNAME; - - if (*offset < size) { - /* still space in the options array */ - r = option_append(message->options, size, offset, code, optlen, optval); - if (r >= 0) - return 0; - else if (r == -ENOBUFS && (file || sname)) { - /* did not fit, but we have more buffers to try - close the options array and move the offset to its end */ - r = option_append(message->options, size, offset, DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - *offset = size; - } else - return r; - } - - if (overload & DHCP_OVERLOAD_FILE) { - file_offset = *offset - size; - - if (file_offset < sizeof(message->file)) { - /* still space in the 'file' array */ - r = option_append(message->file, sizeof(message->file), &file_offset, code, optlen, optval); - if (r >= 0) { - *offset = size + file_offset; - return 0; - } else if (r == -ENOBUFS && sname) { - /* did not fit, but we have more buffers to try - close the file array and move the offset to its end */ - r = option_append(message->options, size, offset, DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - *offset = size + sizeof(message->file); - } else - return r; - } - } - - if (overload & DHCP_OVERLOAD_SNAME) { - sname_offset = *offset - size - (file ? sizeof(message->file) : 0); - - if (sname_offset < sizeof(message->sname)) { - /* still space in the 'sname' array */ - r = option_append(message->sname, sizeof(message->sname), &sname_offset, code, optlen, optval); - if (r >= 0) { - *offset = size + (file ? sizeof(message->file) : 0) + sname_offset; - return 0; - } else { - /* no space, or other error, give up */ - return r; - } - } - } - - return -ENOBUFS; -} - -static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload, - uint8_t *message_type, dhcp_option_cb_t cb, - void *user_data) { - uint8_t code, len; - size_t offset = 0; - - while (offset < buflen) { - switch (options[offset]) { - case DHCP_OPTION_PAD: - offset++; - - break; - - case DHCP_OPTION_END: - return 0; - - case DHCP_OPTION_MESSAGE_TYPE: - if (buflen < offset + 3) - return -ENOBUFS; - - len = options[++offset]; - if (len != 1) - return -EINVAL; - - if (message_type) - *message_type = options[++offset]; - else - offset++; - - offset++; - - break; - - case DHCP_OPTION_OVERLOAD: - if (buflen < offset + 3) - return -ENOBUFS; - - len = options[++offset]; - if (len != 1) - return -EINVAL; - - if (overload) - *overload = options[++offset]; - else - offset++; - - offset++; - - break; - - default: - if (buflen < offset + 3) - return -ENOBUFS; - - code = options[offset]; - len = options[++offset]; - - if (buflen < ++offset + len) - return -EINVAL; - - if (cb) - cb(code, len, &options[offset], user_data); - - offset += len; - - break; - } - } - - if (offset < buflen) - return -EINVAL; - - return 0; -} - -int dhcp_option_parse(DHCPMessage *message, size_t len, - dhcp_option_cb_t cb, void *user_data) { - uint8_t overload = 0; - uint8_t message_type = 0; - int r; - - if (!message) - return -EINVAL; - - if (len < sizeof(DHCPMessage)) - return -EINVAL; - - len -= sizeof(DHCPMessage); - - r = parse_options(message->options, len, &overload, &message_type, - cb, user_data); - if (r < 0) - return r; - - if (overload & DHCP_OVERLOAD_FILE) { - r = parse_options(message->file, sizeof(message->file), - NULL, &message_type, cb, user_data); - if (r < 0) - return r; - } - - if (overload & DHCP_OVERLOAD_SNAME) { - r = parse_options(message->sname, sizeof(message->sname), - NULL, &message_type, cb, user_data); - if (r < 0) - return r; - } - - if (message_type) - return message_type; - - return -ENOMSG; -} diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c deleted file mode 100644 index 5bb065ba..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-packet.c +++ /dev/null @@ -1,204 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. - Copyright (C) 2014 Tom Gundersen - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "config.h" - -#include "nm-sd-adapt.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "list.h" - -#include "dhcp-protocol.h" -#include "dhcp-lease-internal.h" -#include "dhcp-internal.h" -#include "sd-dhcp-lease.h" -#include "sd-dhcp-client.h" - -#define DHCP_CLIENT_MIN_OPTIONS_SIZE 312 - -int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, - uint8_t type, uint16_t arp_type, size_t optlen, - size_t *optoffset) { - size_t offset = 0; - int r; - - assert(op == BOOTREQUEST || op == BOOTREPLY); - assert(arp_type == ARPHRD_ETHER || arp_type == ARPHRD_INFINIBAND); - - message->op = op; - message->htype = arp_type; - message->hlen = (arp_type == ARPHRD_ETHER) ? ETHER_ADDR_LEN : 0; - message->xid = htobe32(xid); - message->magic = htobe32(DHCP_MAGIC_COOKIE); - - r = dhcp_option_append(message, optlen, &offset, 0, - DHCP_OPTION_MESSAGE_TYPE, 1, &type); - if (r < 0) - return r; - - *optoffset = offset; - - return 0; -} - -uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) { - uint64_t *buf_64 = (uint64_t*)buf; - uint64_t *end_64 = buf_64 + (len / sizeof(uint64_t)); - uint64_t sum = 0; - - /* See RFC1071 */ - - while (buf_64 < end_64) { - sum += *buf_64; - if (sum < *buf_64) - /* wrap around in one's complement */ - sum++; - - buf_64 ++; - } - - if (len % sizeof(uint64_t)) { - /* If the buffer is not aligned to 64-bit, we need - to zero-pad the last few bytes and add them in */ - uint64_t buf_tail = 0; - - memcpy(&buf_tail, buf_64, len % sizeof(uint64_t)); - - sum += buf_tail; - if (sum < buf_tail) - /* wrap around */ - sum++; - } - - while (sum >> 16) - sum = (sum & 0xffff) + (sum >> 16); - - return ~sum; -} - -void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr, - uint16_t source_port, be32_t destination_addr, - uint16_t destination_port, uint16_t len) { - packet->ip.version = IPVERSION; - packet->ip.ihl = DHCP_IP_SIZE / 4; - packet->ip.tot_len = htobe16(len); - - packet->ip.tos = IPTOS_CLASS_CS6; - - packet->ip.protocol = IPPROTO_UDP; - packet->ip.saddr = source_addr; - packet->ip.daddr = destination_addr; - - packet->udp.source = htobe16(source_port); - packet->udp.dest = htobe16(destination_port); - - packet->udp.len = htobe16(len - DHCP_IP_SIZE); - - packet->ip.check = packet->udp.len; - packet->udp.check = dhcp_packet_checksum((uint8_t*)&packet->ip.ttl, len - 8); - - packet->ip.ttl = IPDEFTTL; - packet->ip.check = 0; - packet->ip.check = dhcp_packet_checksum((uint8_t*)&packet->ip, DHCP_IP_SIZE); -} - -int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum) { - size_t hdrlen; - - assert(packet); - - /* IP */ - - if (packet->ip.version != IPVERSION) { - log_debug("ignoring packet: not IPv4"); - return -EINVAL; - } - - if (packet->ip.ihl < 5) { - log_debug("ignoring packet: IPv4 IHL (%u words) invalid", - packet->ip.ihl); - return -EINVAL; - } - - hdrlen = packet->ip.ihl * 4; - if (hdrlen < 20) { - log_debug("ignoring packet: IPv4 IHL (%zu bytes) " - "smaller than minimum (20 bytes)", hdrlen); - return -EINVAL; - } - - if (len < hdrlen) { - log_debug("ignoring packet: packet (%zu bytes) " - "smaller than expected (%zu) by IP header", len, - hdrlen); - return -EINVAL; - } - - /* UDP */ - - if (packet->ip.protocol != IPPROTO_UDP) { - log_debug("ignoring packet: not UDP"); - return -EINVAL; - } - - if (len < hdrlen + be16toh(packet->udp.len)) { - log_debug("ignoring packet: packet (%zu bytes) " - "smaller than expected (%zu) by UDP header", len, - hdrlen + be16toh(packet->udp.len)); - return -EINVAL; - } - - if (be16toh(packet->udp.dest) != DHCP_PORT_CLIENT) { - log_debug("ignoring packet: to port %u, which " - "is not the DHCP client port (%u)", - be16toh(packet->udp.dest), DHCP_PORT_CLIENT); - return -EINVAL; - } - - /* checksums - computing these is relatively expensive, so only do it - if all the other checks have passed - */ - - if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen)) { - log_debug("ignoring packet: invalid IP checksum"); - return -EINVAL; - } - - if (checksum && packet->udp.check) { - packet->ip.check = packet->udp.len; - packet->ip.ttl = 0; - - if (dhcp_packet_checksum((uint8_t*)&packet->ip.ttl, - be16toh(packet->udp.len) + 12)) { - log_debug("ignoring packet: invalid UDP checksum"); - return -EINVAL; - } - } - - return 0; -} diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-protocol.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-protocol.h deleted file mode 100644 index aa37e9b0..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp-protocol.h +++ /dev/null @@ -1,142 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "macro.h" -#include "sparse-endian.h" - -struct DHCPMessage { - uint8_t op; - uint8_t htype; - uint8_t hlen; - uint8_t hops; - be32_t xid; - be16_t secs; - be16_t flags; - be32_t ciaddr; - be32_t yiaddr; - be32_t siaddr; - be32_t giaddr; - uint8_t chaddr[16]; - uint8_t sname[64]; - uint8_t file[128]; - be32_t magic; - uint8_t options[0]; -} _packed_; - -typedef struct DHCPMessage DHCPMessage; - -struct DHCPPacket { - struct iphdr ip; - struct udphdr udp; - DHCPMessage dhcp; -} _packed_; - -typedef struct DHCPPacket DHCPPacket; - -#define DHCP_IP_SIZE (int32_t)(sizeof(struct iphdr)) -#define DHCP_IP_UDP_SIZE (int32_t)(sizeof(struct udphdr) + DHCP_IP_SIZE) -#define DHCP_MESSAGE_SIZE (int32_t)(sizeof(DHCPMessage)) -#define DHCP_DEFAULT_MIN_SIZE 576 /* the minimum internet hosts must be able to receive */ -#define DHCP_MIN_OPTIONS_SIZE DHCP_DEFAULT_MIN_SIZE - DHCP_IP_UDP_SIZE - DHCP_MESSAGE_SIZE -#define DHCP_MAGIC_COOKIE (uint32_t)(0x63825363) - -enum { - DHCP_PORT_SERVER = 67, - DHCP_PORT_CLIENT = 68, -}; - -enum DHCPState { - DHCP_STATE_INIT = 0, - DHCP_STATE_SELECTING = 1, - DHCP_STATE_INIT_REBOOT = 2, - DHCP_STATE_REBOOTING = 3, - DHCP_STATE_REQUESTING = 4, - DHCP_STATE_BOUND = 5, - DHCP_STATE_RENEWING = 6, - DHCP_STATE_REBINDING = 7, - DHCP_STATE_STOPPED = 8, -}; - -typedef enum DHCPState DHCPState; - -enum { - BOOTREQUEST = 1, - BOOTREPLY = 2, -}; - -enum { - DHCP_DISCOVER = 1, - DHCP_OFFER = 2, - DHCP_REQUEST = 3, - DHCP_DECLINE = 4, - DHCP_ACK = 5, - DHCP_NAK = 6, - DHCP_RELEASE = 7, - DHCP_INFORM = 8, - DHCP_FORCERENEW = 9, -}; - -enum { - DHCP_OVERLOAD_FILE = 1, - DHCP_OVERLOAD_SNAME = 2, -}; - -enum { - DHCP_OPTION_PAD = 0, - DHCP_OPTION_SUBNET_MASK = 1, - DHCP_OPTION_TIME_OFFSET = 2, - DHCP_OPTION_ROUTER = 3, - DHCP_OPTION_DOMAIN_NAME_SERVER = 6, - DHCP_OPTION_HOST_NAME = 12, - DHCP_OPTION_BOOT_FILE_SIZE = 13, - DHCP_OPTION_DOMAIN_NAME = 15, - DHCP_OPTION_ROOT_PATH = 17, - DHCP_OPTION_ENABLE_IP_FORWARDING = 19, - DHCP_OPTION_ENABLE_IP_FORWARDING_NL = 20, - DHCP_OPTION_POLICY_FILTER = 21, - DHCP_OPTION_INTERFACE_MDR = 22, - DHCP_OPTION_INTERFACE_TTL = 23, - DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT = 24, - DHCP_OPTION_INTERFACE_MTU = 26, - DHCP_OPTION_BROADCAST = 28, - DHCP_OPTION_STATIC_ROUTE = 33, - DHCP_OPTION_NTP_SERVER = 42, - DHCP_OPTION_VENDOR_SPECIFIC = 43, - DHCP_OPTION_REQUESTED_IP_ADDRESS = 50, - DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51, - DHCP_OPTION_OVERLOAD = 52, - DHCP_OPTION_MESSAGE_TYPE = 53, - DHCP_OPTION_SERVER_IDENTIFIER = 54, - DHCP_OPTION_PARAMETER_REQUEST_LIST = 55, - DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57, - DHCP_OPTION_RENEWAL_T1_TIME = 58, - DHCP_OPTION_REBINDING_T2_TIME = 59, - DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, - DHCP_OPTION_CLIENT_IDENTIFIER = 61, - DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, - DHCP_OPTION_END = 255, -}; diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-internal.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-internal.h deleted file mode 100644 index e29e2f0e..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-internal.h +++ /dev/null @@ -1,81 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright (C) 2014 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "nm-sd-adapt.h" - -#include -#include - -#include "sparse-endian.h" -#include "sd-event.h" -#include "list.h" -#include "macro.h" - -typedef struct DHCP6Address DHCP6Address; - -struct DHCP6Address { - LIST_FIELDS(DHCP6Address, addresses); - - struct { - struct in6_addr address; - be32_t lifetime_preferred; - be32_t lifetime_valid; - } iaaddr _packed_; -}; - -struct DHCP6IA { - uint16_t type; - struct { - be32_t id; - be32_t lifetime_t1; - be32_t lifetime_t2; - } _packed_; - sd_event_source *timeout_t1; - sd_event_source *timeout_t2; - - LIST_HEAD(DHCP6Address, addresses); -}; - -typedef struct DHCP6IA DHCP6IA; - -#define log_dhcp6_client(p, fmt, ...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__) - -int dhcp_network_icmp6_bind_router_solicitation(int index); -int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr); - -int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, - size_t optlen, const void *optval); -int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia); -int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, - size_t *optlen, uint8_t **optvalue); -int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, - DHCP6IA *ia); - -int dhcp6_network_bind_udp_socket(int index, struct in6_addr *address); -int dhcp6_network_send_udp_socket(int s, struct in6_addr *address, - const void *packet, size_t len); - -const char *dhcp6_message_type_to_string(int s) _const_; -int dhcp6_message_type_from_string(const char *s) _pure_; -const char *dhcp6_message_status_to_string(int s) _const_; -int dhcp6_message_status_from_string(const char *s) _pure_; diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-lease-internal.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-lease-internal.h deleted file mode 100644 index 9f7826c4..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-lease-internal.h +++ /dev/null @@ -1,64 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "nm-sd-adapt.h" - -#include - -#include "refcnt.h" - -#include "sd-dhcp6-lease.h" -#include "dhcp6-internal.h" - -struct sd_dhcp6_lease { - RefCount n_ref; - - uint8_t *serverid; - size_t serverid_len; - uint8_t preference; - bool rapid_commit; - - DHCP6IA ia; - - DHCP6Address *addr_iter; -}; - -int dhcp6_lease_clear_timers(DHCP6IA *ia); -int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire); -DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia); - -int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id, - size_t len); -int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len); -int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference); -int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference); -int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease); -int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit); - -int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid); - -int dhcp6_lease_new(sd_dhcp6_lease **ret); - -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_lease*, sd_dhcp6_lease_unref); -#define _cleanup_dhcp6_lease_free_ _cleanup_(sd_dhcp6_lease_unrefp) diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-network.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-network.c deleted file mode 100644 index fbb20ef9..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-network.c +++ /dev/null @@ -1,198 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "config.h" - -#include "nm-sd-adapt.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "socket-util.h" - -#include "dhcp6-internal.h" -#include "dhcp6-protocol.h" - -#define IN6ADDR_ALL_ROUTERS_MULTICAST_INIT \ - { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } } } - -#define IN6ADDR_ALL_NODES_MULTICAST_INIT \ - { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } } - -int dhcp_network_icmp6_bind_router_solicitation(int index) -{ - struct icmp6_filter filter = { }; - struct ipv6_mreq mreq = { - .ipv6mr_multiaddr = IN6ADDR_ALL_NODES_MULTICAST_INIT, - .ipv6mr_interface = index, - }; - _cleanup_close_ int s = -1; - int r, zero = 0, hops = 255; - - s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, - IPPROTO_ICMPV6); - if (s < 0) - return -errno; - - ICMP6_FILTER_SETBLOCKALL(&filter); - ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filter); - r = setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, - sizeof(filter)); - if (r < 0) - return -errno; - - /* RFC 3315, section 6.7, bullet point 2 may indicate that an - IPV6_PKTINFO socket option also applies for ICMPv6 multicast. - Empirical experiments indicates otherwise and therefore an - IPV6_MULTICAST_IF socket option is used here instead */ - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &index, - sizeof(index)); - if (r < 0) - return -errno; - - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &zero, - sizeof(zero)); - if (r < 0) - return -errno; - - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, - sizeof(hops)); - if (r < 0) - return -errno; - - r = setsockopt(s, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, - sizeof(mreq)); - if (r < 0) - return -errno; - - r = s; - s = -1; - return r; -} - -int dhcp_network_icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) -{ - struct sockaddr_in6 dst = { - .sin6_family = AF_INET6, - .sin6_addr = IN6ADDR_ALL_ROUTERS_MULTICAST_INIT, - }; - struct { - struct nd_router_solicit rs; - struct nd_opt_hdr rs_opt; - struct ether_addr rs_opt_mac; - } _packed_ rs = { - .rs.nd_rs_type = ND_ROUTER_SOLICIT, - }; - struct iovec iov[1] = { - { &rs, }, - }; - struct msghdr msg = { - .msg_name = &dst, - .msg_namelen = sizeof(dst), - .msg_iov = iov, - .msg_iovlen = 1, - }; - int r; - - if (ether_addr) { - memcpy(&rs.rs_opt_mac, ether_addr, ETH_ALEN); - rs.rs_opt.nd_opt_type = ND_OPT_SOURCE_LINKADDR; - rs.rs_opt.nd_opt_len = 1; - iov[0].iov_len = sizeof(rs); - } else - iov[0].iov_len = sizeof(rs.rs); - - r = sendmsg(s, &msg, 0); - if (r < 0) - return -errno; - - return 0; -} - -int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { - struct in6_pktinfo pktinfo = { - .ipi6_ifindex = index, - }; - union sockaddr_union src = { - .in6.sin6_family = AF_INET6, - .in6.sin6_port = htobe16(DHCP6_PORT_CLIENT), - .in6.sin6_addr = IN6ADDR_ANY_INIT, - }; - _cleanup_close_ int s = -1; - int r, off = 0, on = 1; - - if (local_address) - memcpy(&src.in6.sin6_addr, local_address, - sizeof(src.in6.sin6_addr)); - - s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, - IPPROTO_UDP); - if (s < 0) - return -errno; - - r = setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &pktinfo, - sizeof(pktinfo)); - if (r < 0) - return -errno; - - r = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); - if (r < 0) - return -errno; - - r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off)); - if (r < 0) - return -errno; - - r = bind(s, &src.sa, sizeof(src.in6)); - if (r < 0) - return -errno; - - r = s; - s = -1; - return r; -} - -int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address, - const void *packet, size_t len) { - union sockaddr_union dest = { - .in6.sin6_family = AF_INET6, - .in6.sin6_port = htobe16(DHCP6_PORT_SERVER), - }; - int r; - - assert(server_address); - - memcpy(&dest.in6.sin6_addr, server_address, sizeof(dest.in6.sin6_addr)); - - r = sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in6)); - if (r < 0) - return -errno; - - return 0; -} diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c deleted file mode 100644 index 3d6e2462..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-option.c +++ /dev/null @@ -1,323 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright (C) 2014 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "config.h" - -#include "nm-sd-adapt.h" - -#include -#include -#include - -#include "sparse-endian.h" -#include "unaligned.h" -#include "util.h" - -#include "dhcp6-internal.h" -#include "dhcp6-protocol.h" - -#define DHCP6_OPTION_IA_NA_LEN 12 -#define DHCP6_OPTION_IA_TA_LEN 4 - -typedef struct DHCP6Option { - be16_t code; - be16_t len; - uint8_t data[]; -} _packed_ DHCP6Option; - -static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode, - size_t optlen) { - DHCP6Option *option = (DHCP6Option*) *buf; - - assert_return(buf, -EINVAL); - assert_return(*buf, -EINVAL); - assert_return(buflen, -EINVAL); - - if (optlen > 0xffff || *buflen < optlen + sizeof(DHCP6Option)) - return -ENOBUFS; - - option->code = htobe16(optcode); - option->len = htobe16(optlen); - - *buf += sizeof(DHCP6Option); - *buflen -= sizeof(DHCP6Option); - - return 0; -} - -int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, - size_t optlen, const void *optval) { - int r; - - assert_return(optval || optlen == 0, -EINVAL); - - r = option_append_hdr(buf, buflen, code, optlen); - if (r < 0) - return r; - - if (optval) - memcpy(*buf, optval, optlen); - - *buf += optlen; - *buflen -= optlen; - - return 0; -} - -int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { - uint16_t len; - uint8_t *ia_hdr; - size_t ia_buflen, ia_addrlen = 0; - DHCP6Address *addr; - int r; - - assert_return(buf && *buf && buflen && ia, -EINVAL); - - switch (ia->type) { - case DHCP6_OPTION_IA_NA: - len = DHCP6_OPTION_IA_NA_LEN; - break; - - case DHCP6_OPTION_IA_TA: - len = DHCP6_OPTION_IA_TA_LEN; - break; - - default: - return -EINVAL; - } - - if (*buflen < len) - return -ENOBUFS; - - ia_hdr = *buf; - ia_buflen = *buflen; - - *buf += sizeof(DHCP6Option); - *buflen -= sizeof(DHCP6Option); - - memcpy(*buf, &ia->id, len); - - *buf += len; - *buflen -= len; - - LIST_FOREACH(addresses, addr, ia->addresses) { - r = option_append_hdr(buf, buflen, DHCP6_OPTION_IAADDR, - sizeof(addr->iaaddr)); - if (r < 0) - return r; - - memcpy(*buf, &addr->iaaddr, sizeof(addr->iaaddr)); - - *buf += sizeof(addr->iaaddr); - *buflen -= sizeof(addr->iaaddr); - - ia_addrlen += sizeof(DHCP6Option) + sizeof(addr->iaaddr); - } - - r = option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len + ia_addrlen); - if (r < 0) - return r; - - return 0; -} - - -static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen) { - DHCP6Option *option = (DHCP6Option*) *buf; - uint16_t len; - - assert_return(buf, -EINVAL); - assert_return(optcode, -EINVAL); - assert_return(optlen, -EINVAL); - - if (*buflen < sizeof(DHCP6Option)) - return -ENOMSG; - - len = be16toh(option->len); - - if (len > *buflen) - return -ENOMSG; - - *optcode = be16toh(option->code); - *optlen = len; - - *buf += 4; - *buflen -= 4; - - return 0; -} - -int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, - size_t *optlen, uint8_t **optvalue) { - int r; - - assert_return(buf && buflen && optcode && optlen && optvalue, -EINVAL); - - r = option_parse_hdr(buf, buflen, optcode, optlen); - if (r < 0) - return r; - - if (*optlen > *buflen) - return -ENOBUFS; - - *optvalue = *buf; - *buflen -= *optlen; - *buf += *optlen; - - return 0; -} - -int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, - DHCP6IA *ia) { - int r; - uint16_t opt, status; - size_t optlen; - size_t iaaddr_offset; - DHCP6Address *addr; - uint32_t lt_t1, lt_t2, lt_valid, lt_pref, lt_min = ~0; - - assert_return(ia, -EINVAL); - assert_return(!ia->addresses, -EINVAL); - - switch (iatype) { - case DHCP6_OPTION_IA_NA: - - if (*buflen < DHCP6_OPTION_IA_NA_LEN + sizeof(DHCP6Option) + - sizeof(addr->iaaddr)) { - r = -ENOBUFS; - goto error; - } - - iaaddr_offset = DHCP6_OPTION_IA_NA_LEN; - memcpy(&ia->id, *buf, iaaddr_offset); - - lt_t1 = be32toh(ia->lifetime_t1); - lt_t2 = be32toh(ia->lifetime_t2); - - if (lt_t1 && lt_t2 && lt_t1 > lt_t2) { - log_dhcp6_client(client, "IA T1 %ds > T2 %ds", - lt_t1, lt_t2); - r = -EINVAL; - goto error; - } - - break; - - case DHCP6_OPTION_IA_TA: - if (*buflen < DHCP6_OPTION_IA_TA_LEN + sizeof(DHCP6Option) + - sizeof(addr->iaaddr)) { - r = -ENOBUFS; - goto error; - } - - iaaddr_offset = DHCP6_OPTION_IA_TA_LEN; - memcpy(&ia->id, *buf, iaaddr_offset); - - ia->lifetime_t1 = 0; - ia->lifetime_t2 = 0; - - break; - - default: - r = -ENOMSG; - goto error; - } - - ia->type = iatype; - - *buflen -= iaaddr_offset; - *buf += iaaddr_offset; - - while ((r = option_parse_hdr(buf, buflen, &opt, &optlen)) >= 0) { - - switch (opt) { - case DHCP6_OPTION_IAADDR: - - addr = new0(DHCP6Address, 1); - if (!addr) { - r = -ENOMEM; - goto error; - } - - LIST_INIT(addresses, addr); - - memcpy(&addr->iaaddr, *buf, sizeof(addr->iaaddr)); - - lt_valid = be32toh(addr->iaaddr.lifetime_valid); - lt_pref = be32toh(addr->iaaddr.lifetime_valid); - - if (!lt_valid || lt_pref > lt_valid) { - log_dhcp6_client(client, "IA preferred %ds > valid %ds", - lt_pref, lt_valid); - free(addr); - } else { - LIST_PREPEND(addresses, ia->addresses, addr); - if (lt_valid < lt_min) - lt_min = lt_valid; - } - - break; - - case DHCP6_OPTION_STATUS_CODE: - if (optlen < sizeof(status)) - break; - - status = (*buf)[0] << 8 | (*buf)[1]; - if (status) { - log_dhcp6_client(client, "IA status %d", - status); - r = -EINVAL; - goto error; - } - - break; - - default: - log_dhcp6_client(client, "Unknown IA option %d", opt); - break; - } - - *buflen -= optlen; - *buf += optlen; - } - - if (r == -ENOMSG) - r = 0; - - if (!ia->lifetime_t1 && !ia->lifetime_t2) { - lt_t1 = lt_min / 2; - lt_t2 = lt_min / 10 * 8; - ia->lifetime_t1 = htobe32(lt_t1); - ia->lifetime_t2 = htobe32(lt_t2); - - log_dhcp6_client(client, "Computed IA T1 %ds and T2 %ds as both were zero", - lt_t1, lt_t2); - } - - if (*buflen) - r = -ENOMSG; - -error: - *buf += *buflen; - *buflen = 0; - - return r; -} diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-protocol.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-protocol.h deleted file mode 100644 index eaa67171..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/dhcp6-protocol.h +++ /dev/null @@ -1,141 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright (C) 2014 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "macro.h" -#include "sparse-endian.h" - -struct DHCP6Message { - union { - struct { - uint8_t type; - uint8_t _pad[3]; - } _packed_; - be32_t transaction_id; - }; -} _packed_; - -typedef struct DHCP6Message DHCP6Message; - -#define DHCP6_MIN_OPTIONS_SIZE \ - 1280 - sizeof(struct ip6_hdr) - sizeof(struct udphdr) - -#define IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT \ - { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02 } } } - -enum { - DHCP6_PORT_SERVER = 547, - DHCP6_PORT_CLIENT = 546, -}; - -#define DHCP6_SOL_MAX_DELAY 1 * USEC_PER_SEC -#define DHCP6_SOL_TIMEOUT 1 * USEC_PER_SEC -#define DHCP6_SOL_MAX_RT 120 * USEC_PER_SEC -#define DHCP6_REQ_TIMEOUT 1 * USEC_PER_SEC -#define DHCP6_REQ_MAX_RT 120 * USEC_PER_SEC -#define DHCP6_REQ_MAX_RC 10 -#define DHCP6_REN_TIMEOUT 10 * USEC_PER_SEC -#define DHCP6_REN_MAX_RT 600 * USEC_PER_SEC -#define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC -#define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC - -enum { - DHCP6_DUID_LLT = 1, - DHCP6_DUID_EN = 2, - DHCP6_DUID_LL = 3, - DHCP6_DUID_UUID = 4, -}; - -enum DHCP6State { - DHCP6_STATE_STOPPED = 0, - DHCP6_STATE_SOLICITATION = 2, - DHCP6_STATE_REQUEST = 3, - DHCP6_STATE_BOUND = 4, - DHCP6_STATE_RENEW = 5, - DHCP6_STATE_REBIND = 6, -}; - -enum { - DHCP6_SOLICIT = 1, - DHCP6_ADVERTISE = 2, - DHCP6_REQUEST = 3, - DHCP6_CONFIRM = 4, - DHCP6_RENEW = 5, - DHCP6_REBIND = 6, - DHCP6_REPLY = 7, - DHCP6_RELEASE = 8, - DHCP6_DECLINE = 9, - DHCP6_RECONFIGURE = 10, - DHCP6_INFORMATION_REQUEST = 11, - DHCP6_RELAY_FORW = 12, - DHCP6_RELAY_REPL = 13, - _DHCP6_MESSAGE_MAX = 14, -}; - -enum { - DHCP6_OPTION_CLIENTID = 1, - DHCP6_OPTION_SERVERID = 2, - DHCP6_OPTION_IA_NA = 3, - DHCP6_OPTION_IA_TA = 4, - DHCP6_OPTION_IAADDR = 5, - DHCP6_OPTION_ORO = 6, - DHCP6_OPTION_PREFERENCE = 7, - DHCP6_OPTION_ELAPSED_TIME = 8, - DHCP6_OPTION_RELAY_MSG = 9, - /* option code 10 is unassigned */ - DHCP6_OPTION_AUTH = 11, - DHCP6_OPTION_UNICAST = 12, - DHCP6_OPTION_STATUS_CODE = 13, - DHCP6_OPTION_RAPID_COMMIT = 14, - DHCP6_OPTION_USER_CLASS = 15, - DHCP6_OPTION_VENDOR_CLASS = 16, - DHCP6_OPTION_VENDOR_OPTS = 17, - DHCP6_OPTION_INTERFACE_ID = 18, - DHCP6_OPTION_RECONF_MSG = 19, - DHCP6_OPTION_RECONF_ACCEPT = 20, - - DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */ - DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */ - - DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075 */ - - /* option code 35 is unassigned */ - - DHCP6_OPTION_NTP_SERVER = 56, /* RFC 5908 */ - - /* option codes 89-142 are unassigned */ - /* option codes 144-65535 are unassigned */ -}; - -enum { - DHCP6_STATUS_SUCCESS = 0, - DHCP6_STATUS_UNSPEC_FAIL = 1, - DHCP6_STATUS_NO_ADDRS_AVAIL = 2, - DHCP6_STATUS_NO_BINDING = 3, - DHCP6_STATUS_NOT_ON_LINK = 4, - DHCP6_STATUS_USE_MULTICAST = 5, - _DHCP6_STATUS_MAX = 6, -}; diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c deleted file mode 100644 index b9334bd6..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.c +++ /dev/null @@ -1,484 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright (C) 2013 Tom Gundersen - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "config.h" - -#include "nm-sd-adapt.h" - -#include -#include -#include -#include - -#if 0 /* NM_IGNORED */ -#include "strv.h" -#include "siphash24.h" -#include "libudev-private.h" -#endif -#include "dhcp-lease-internal.h" -#if 0 /* NM_IGNORED */ -#include "log.h" -#include "utf8.h" -#endif -#include "util.h" -#if 0 /* NM_IGNORED */ -#include "conf-parser.h" -#include "condition.h" -#endif -#include "network-internal.h" - -#if 0 /* NM_IGNORED */ -const char *net_get_name(struct udev_device *device) { - const char *name, *field; - - assert(device); - - /* fetch some persistent data unique (on this machine) to this device */ - FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") { - name = udev_device_get_property_value(device, field); - if (name) - return name; - } - - return NULL; -} - -#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a) - -int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]) { - size_t l, sz = 0; - const char *name = NULL; - int r; - uint8_t *v; - - assert(device); - - name = net_get_name(device); - if (!name) - return -ENOENT; - - l = strlen(name); - sz = sizeof(sd_id128_t) + l; - v = alloca(sz); - - /* fetch some persistent data unique to this machine */ - r = sd_id128_get_machine((sd_id128_t*) v); - if (r < 0) - return r; - memcpy(v + sizeof(sd_id128_t), name, l); - - /* Let's hash the machine ID plus the device name. We - * use a fixed, but originally randomly created hash - * key here. */ - siphash24(result, v, sz, HASH_KEY.bytes); - - return 0; -} - -bool net_match_config(const struct ether_addr *match_mac, - const char *match_path, - const char *match_driver, - const char *match_type, - const char *match_name, - Condition *match_host, - Condition *match_virt, - Condition *match_kernel, - Condition *match_arch, - const struct ether_addr *dev_mac, - const char *dev_path, - const char *dev_parent_driver, - const char *dev_driver, - const char *dev_type, - const char *dev_name) { - - if (match_host && !condition_test(match_host)) - return 0; - - if (match_virt && !condition_test(match_virt)) - return 0; - - if (match_kernel && !condition_test(match_kernel)) - return 0; - - if (match_arch && !condition_test(match_arch)) - return 0; - - if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN))) - return 0; - - if (match_path && (!dev_path || fnmatch(match_path, dev_path, 0))) - return 0; - - if (match_driver) { - if (dev_parent_driver && !streq(match_driver, dev_parent_driver)) - return 0; - else if (!streq_ptr(match_driver, dev_driver)) - return 0; - } - - if (match_type && !streq_ptr(match_type, dev_type)) - return 0; - - if (match_name && (!dev_name || fnmatch(match_name, dev_name, 0))) - return 0; - - return 1; -} - -int config_parse_net_condition(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - ConditionType cond = ltype; - Condition **ret = data; - bool negate; - Condition *c; - _cleanup_free_ char *s = NULL; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - negate = rvalue[0] == '!'; - if (negate) - rvalue++; - - s = strdup(rvalue); - if (!s) - return log_oom(); - - c = condition_new(cond, s, false, negate); - if (!c) - return log_oom(); - - if (*ret) - condition_free(*ret); - - *ret = c; - return 0; -} - -int config_parse_ifname(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char **s = data; - _cleanup_free_ char *n = NULL; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - n = strdup(rvalue); - if (!n) - return log_oom(); - - if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue); - return 0; - } - - free(*s); - if (*n) { - *s = n; - n = NULL; - } else - *s = NULL; - - return 0; -} - -int config_parse_ifalias(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char **s = data; - char *n; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - n = strdup(rvalue); - if (!n) - return log_oom(); - - if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue); - free(n); - return 0; - } - - free(*s); - if (*n) - *s = n; - else { - free(n); - *s = NULL; - } - - return 0; -} - -int config_parse_hwaddr(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - struct ether_addr **hwaddr = data; - struct ether_addr *n; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - n = new0(struct ether_addr, 1); - if (!n) - return log_oom(); - - r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", - &n->ether_addr_octet[0], - &n->ether_addr_octet[1], - &n->ether_addr_octet[2], - &n->ether_addr_octet[3], - &n->ether_addr_octet[4], - &n->ether_addr_octet[5]); - if (r != 6) { - log_syntax(unit, LOG_ERR, filename, line, EINVAL, - "Not a valid MAC address, ignoring assignment: %s", rvalue); - free(n); - return 0; - } - - free(*hwaddr); - *hwaddr = n; - - return 0; -} -#endif - -void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) { - unsigned i; - - assert(f); - assert(addresses); - assert(size); - - for (i = 0; i < size; i++) - fprintf(f, "%s%s", inet_ntoa(addresses[i]), - (i < (size - 1)) ? " ": ""); -} - -int deserialize_in_addrs(struct in_addr **ret, const char *string) { - _cleanup_free_ struct in_addr *addresses = NULL; - int size = 0; - const char *word, *state; - size_t len; - - assert(ret); - assert(string); - - FOREACH_WORD(word, len, string, state) { - _cleanup_free_ char *addr_str = NULL; - struct in_addr *new_addresses; - int r; - - new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr)); - if (!new_addresses) - return -ENOMEM; - else - addresses = new_addresses; - - addr_str = strndup(word, len); - if (!addr_str) - return -ENOMEM; - - r = inet_pton(AF_INET, addr_str, &(addresses[size])); - if (r <= 0) - continue; - - size ++; - } - - *ret = addresses; - addresses = NULL; - - return size; -} - -int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { - _cleanup_free_ struct in6_addr *addresses = NULL; - int size = 0; - const char *word, *state; - size_t len; - - assert(ret); - assert(string); - - FOREACH_WORD(word, len, string, state) { - _cleanup_free_ char *addr_str = NULL; - struct in6_addr *new_addresses; - int r; - - new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr)); - if (!new_addresses) - return -ENOMEM; - else - addresses = new_addresses; - - addr_str = strndup(word, len); - if (!addr_str) - return -ENOMEM; - - r = inet_pton(AF_INET6, addr_str, &(addresses[size])); - if (r <= 0) - continue; - - size++; - } - - *ret = addresses; - addresses = NULL; - - return size; -} - -void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) { - unsigned i; - - assert(f); - assert(key); - assert(routes); - assert(size); - - fprintf(f, "%s=", key); - - for (i = 0; i < size; i++) { - fprintf(f, "%s/%" PRIu8, inet_ntoa(routes[i].dst_addr), - routes[i].dst_prefixlen); - fprintf(f, ",%s%s", inet_ntoa(routes[i].gw_addr), - (i < (size - 1)) ? " ": ""); - } - - fputs("\n", f); -} - -int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) { - _cleanup_free_ struct sd_dhcp_route *routes = NULL; - size_t size = 0, allocated = 0; - const char *word, *state; - size_t len; - - assert(ret); - assert(ret_size); - assert(ret_allocated); - assert(string); - - FOREACH_WORD(word, len, string, state) { - /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */ - _cleanup_free_ char* entry = NULL; - char *tok, *tok_end; - unsigned n; - int r; - - if (!GREEDY_REALLOC(routes, allocated, size + 1)) - return -ENOMEM; - - entry = strndup(word, len); - if(!entry) - return -ENOMEM; - - tok = entry; - - /* get the subnet */ - tok_end = strchr(tok, '/'); - if (!tok_end) - continue; - *tok_end = '\0'; - - r = inet_aton(tok, &routes[size].dst_addr); - if (r == 0) - continue; - - tok = tok_end + 1; - - /* get the prefixlen */ - tok_end = strchr(tok, ','); - if (!tok_end) - continue; - - *tok_end = '\0'; - - r = safe_atou(tok, &n); - if (r < 0 || n > 32) - continue; - - routes[size].dst_prefixlen = (uint8_t) n; - tok = tok_end + 1; - - /* get the gateway */ - r = inet_aton(tok, &routes[size].gw_addr); - if (r == 0) - continue; - - size++; - } - - *ret_size = size; - *ret_allocated = allocated; - *ret = routes; - routes = NULL; - - return 0; -} diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h deleted file mode 100644 index f87c863d..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/network-internal.h +++ /dev/null @@ -1,78 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright (C) 2013 Tom Gundersen - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "nm-sd-adapt.h" - -#include -#include -#include - -#if 0 /* NM_IGNORED */ -#include "udev.h" -#include "condition.h" - -bool net_match_config(const struct ether_addr *match_mac, - const char *match_path, - const char *match_driver, - const char *match_type, - const char *match_name, - Condition *match_host, - Condition *match_virt, - Condition *match_kernel, - Condition *match_arch, - const struct ether_addr *dev_mac, - const char *dev_path, - const char *dev_parent_driver, - const char *dev_driver, - const char *dev_type, - const char *dev_name); - -int config_parse_net_condition(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_hwaddr(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_ifname(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int config_parse_ifalias(const char *unit, const char *filename, unsigned line, - const char *section, unsigned section_line, const char *lvalue, - int ltype, const char *rvalue, void *data, void *userdata); - -int net_get_unique_predictable_data(struct udev_device *device, uint8_t result[8]); -const char *net_get_name(struct udev_device *device); -#endif - -void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size); -int deserialize_in_addrs(struct in_addr **addresses, const char *string); -int deserialize_in6_addrs(struct in6_addr **addresses, const char *string); - -/* don't include "dhcp-lease-internal.h" as it causes conflicts between netinet/ip.h and linux/ip.h */ -struct sd_dhcp_route; - -void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size); -int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string); diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c deleted file mode 100644 index 3e4cd8d9..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-client.c +++ /dev/null @@ -1,1726 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "config.h" - -#include "nm-sd-adapt.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "list.h" -#include "refcnt.h" -#include "async.h" - -#include "dhcp-protocol.h" -#include "dhcp-internal.h" -#include "dhcp-lease-internal.h" -#include "sd-dhcp-client.h" - -#define MAX_CLIENT_ID_LEN 64 /* Arbitrary limit */ -#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN - -struct sd_dhcp_client { - RefCount n_ref; - - DHCPState state; - sd_event *event; - int event_priority; - sd_event_source *timeout_resend; - int index; - int fd; - union sockaddr_union link; - sd_event_source *receive_message; - bool request_broadcast; - uint8_t *req_opts; - size_t req_opts_allocated; - size_t req_opts_size; - be32_t last_addr; - uint8_t mac_addr[MAX_MAC_ADDR_LEN]; - size_t mac_addr_len; - uint16_t arp_type; - union { - struct { - uint8_t type; /* 0: Generic (non-LL) (RFC 2132) */ - uint8_t data[MAX_CLIENT_ID_LEN]; - } _packed_ gen; - struct { - uint8_t type; /* 1: Ethernet Link-Layer (RFC 2132) */ - uint8_t haddr[ETH_ALEN]; - } _packed_ eth; - struct { - uint8_t type; /* 2 - 254: ARP/Link-Layer (RFC 2132) */ - uint8_t haddr[0]; - } _packed_ ll; - struct { - uint8_t type; /* 255: Node-specific (RFC 4361) */ - uint8_t iaid[4]; - uint8_t duid[MAX_CLIENT_ID_LEN - 4]; - } _packed_ ns; - struct { - uint8_t type; - uint8_t data[MAX_CLIENT_ID_LEN]; - } _packed_ raw; - } client_id; - size_t client_id_len; - char *hostname; - char *vendor_class_identifier; - uint32_t mtu; - uint32_t xid; - usec_t start_time; - unsigned int attempt; - usec_t request_sent; - sd_event_source *timeout_t1; - sd_event_source *timeout_t2; - sd_event_source *timeout_expire; - sd_dhcp_client_cb_t cb; - void *userdata; - sd_dhcp_lease *lease; -}; - -static const uint8_t default_req_opts[] = { - DHCP_OPTION_SUBNET_MASK, - DHCP_OPTION_ROUTER, - DHCP_OPTION_HOST_NAME, - DHCP_OPTION_DOMAIN_NAME, - DHCP_OPTION_DOMAIN_NAME_SERVER, - DHCP_OPTION_NTP_SERVER, -}; - -static int client_receive_message_raw(sd_event_source *s, int fd, - uint32_t revents, void *userdata); -static int client_receive_message_udp(sd_event_source *s, int fd, - uint32_t revents, void *userdata); -static void client_stop(sd_dhcp_client *client, int error); - -int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb, - void *userdata) { - assert_return(client, -EINVAL); - - client->cb = cb; - client->userdata = userdata; - - return 0; -} - -int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) { - assert_return(client, -EINVAL); - - client->request_broadcast = !!broadcast; - - return 0; -} - -int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) { - size_t i; - - assert_return(client, -EINVAL); - assert_return (IN_SET(client->state, DHCP_STATE_INIT, - DHCP_STATE_STOPPED), -EBUSY); - - switch(option) { - case DHCP_OPTION_PAD: - case DHCP_OPTION_OVERLOAD: - case DHCP_OPTION_MESSAGE_TYPE: - case DHCP_OPTION_PARAMETER_REQUEST_LIST: - case DHCP_OPTION_END: - return -EINVAL; - - default: - break; - } - - for (i = 0; i < client->req_opts_size; i++) - if (client->req_opts[i] == option) - return -EEXIST; - - if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated, - client->req_opts_size + 1)) - return -ENOMEM; - - client->req_opts[client->req_opts_size++] = option; - - return 0; -} - -int sd_dhcp_client_set_request_address(sd_dhcp_client *client, - const struct in_addr *last_addr) { - assert_return(client, -EINVAL); - assert_return (IN_SET(client->state, DHCP_STATE_INIT, - DHCP_STATE_STOPPED), -EBUSY); - - if (last_addr) - client->last_addr = last_addr->s_addr; - else - client->last_addr = INADDR_ANY; - - return 0; -} - -int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) { - assert_return(client, -EINVAL); - assert_return (IN_SET(client->state, DHCP_STATE_INIT, - DHCP_STATE_STOPPED), -EBUSY); - assert_return(interface_index > 0, -EINVAL); - - client->index = interface_index; - - return 0; -} - -int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, - size_t addr_len, uint16_t arp_type) { - DHCP_CLIENT_DONT_DESTROY(client); - bool need_restart = false; - - assert_return(client, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL); - assert_return(arp_type > 0, -EINVAL); - - if (arp_type == ARPHRD_ETHER) - assert_return(addr_len == ETH_ALEN, -EINVAL); - else if (arp_type == ARPHRD_INFINIBAND) - assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); - else - return -EINVAL; - - if (client->mac_addr_len == addr_len && - memcmp(&client->mac_addr, addr, addr_len) == 0) - return 0; - - if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { - log_dhcp_client(client, "Changing MAC address on running DHCP " - "client, restarting"); - need_restart = true; - client_stop(client, DHCP_EVENT_STOP); - } - - memcpy(&client->mac_addr, addr, addr_len); - client->mac_addr_len = addr_len; - client->arp_type = arp_type; - - if (need_restart && client->state != DHCP_STATE_STOPPED) - sd_dhcp_client_start(client); - - return 0; -} - -int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, - const uint8_t **data, size_t *data_len) { - - assert_return(client, -EINVAL); - assert_return(type, -EINVAL); - assert_return(data, -EINVAL); - assert_return(data_len, -EINVAL); - - *type = 0; - *data = NULL; - *data_len = 0; - if (client->client_id_len) { - *type = client->client_id.raw.type; - *data = client->client_id.raw.data; - *data_len = client->client_id_len - - sizeof (client->client_id.raw.type); - } - - return 0; -} - -int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, - const uint8_t *data, size_t data_len) { - DHCP_CLIENT_DONT_DESTROY(client); - bool need_restart = false; - - assert_return(client, -EINVAL); - assert_return(data, -EINVAL); - assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL); - - switch (type) { - case ARPHRD_ETHER: - if (data_len != ETH_ALEN) - return -EINVAL; - break; - case ARPHRD_INFINIBAND: - if (data_len != INFINIBAND_ALEN) - return -EINVAL; - break; - default: - break; - } - - if (client->client_id_len == data_len + sizeof (client->client_id.raw.type) && - client->client_id.raw.type == type && - memcmp(&client->client_id.raw.data, data, data_len) == 0) - return 0; - - if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { - log_dhcp_client(client, "Changing client ID on running DHCP " - "client, restarting"); - need_restart = true; - client_stop(client, DHCP_EVENT_STOP); - } - - client->client_id.raw.type = type; - memcpy(&client->client_id.raw.data, data, data_len); - client->client_id_len = data_len + sizeof (client->client_id.raw.type); - - if (need_restart && client->state != DHCP_STATE_STOPPED) - sd_dhcp_client_start(client); - - return 0; -} - -int sd_dhcp_client_set_hostname(sd_dhcp_client *client, - const char *hostname) { - char *new_hostname = NULL; - - assert_return(client, -EINVAL); - - if (streq_ptr(client->hostname, hostname)) - return 0; - - if (hostname) { - new_hostname = strdup(hostname); - if (!new_hostname) - return -ENOMEM; - } - - free(client->hostname); - client->hostname = new_hostname; - - return 0; -} - -int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, - const char *vci) { - char *new_vci = NULL; - - assert_return(client, -EINVAL); - - new_vci = strdup(vci); - if (!new_vci) - return -ENOMEM; - - free(client->vendor_class_identifier); - - client->vendor_class_identifier = new_vci; - - return 0; -} - -int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) { - assert_return(client, -EINVAL); - assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE); - - client->mtu = mtu; - - return 0; -} - -int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { - assert_return(client, -EINVAL); - assert_return(ret, -EINVAL); - - if (client->state != DHCP_STATE_BOUND && - client->state != DHCP_STATE_RENEWING && - client->state != DHCP_STATE_REBINDING) - return -EADDRNOTAVAIL; - - *ret = sd_dhcp_lease_ref(client->lease); - - return 0; -} - -static void client_notify(sd_dhcp_client *client, int event) { - if (client->cb) - client->cb(client, event, client->userdata); -} - -static int client_initialize(sd_dhcp_client *client) { - assert_return(client, -EINVAL); - - client->receive_message = - sd_event_source_unref(client->receive_message); - - client->fd = asynchronous_close(client->fd); - - client->timeout_resend = sd_event_source_unref(client->timeout_resend); - - client->timeout_t1 = sd_event_source_unref(client->timeout_t1); - client->timeout_t2 = sd_event_source_unref(client->timeout_t2); - client->timeout_expire = sd_event_source_unref(client->timeout_expire); - - client->attempt = 1; - - client->state = DHCP_STATE_INIT; - client->xid = 0; - - if (client->lease) - client->lease = sd_dhcp_lease_unref(client->lease); - - return 0; -} - -static void client_stop(sd_dhcp_client *client, int error) { - assert(client); - - if (error < 0) - log_dhcp_client(client, "STOPPED: %s", strerror(-error)); - else if (error == DHCP_EVENT_STOP) - log_dhcp_client(client, "STOPPED"); - else - log_dhcp_client(client, "STOPPED: Unknown event"); - - client_notify(client, error); - - client_initialize(client); -} - -static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, - uint8_t type, size_t *_optlen, size_t *_optoffset) { - _cleanup_free_ DHCPPacket *packet = NULL; - size_t optlen, optoffset, size; - be16_t max_size; - usec_t time_now; - uint16_t secs; - int r; - - assert(client); - assert(client->start_time); - assert(ret); - assert(_optlen); - assert(_optoffset); - assert(type == DHCP_DISCOVER || type == DHCP_REQUEST); - - /* See RFC2131 section 4.4.1 */ - - optlen = DHCP_MIN_OPTIONS_SIZE; - size = sizeof(DHCPPacket) + optlen; - - packet = malloc0(size); - if (!packet) - return -ENOMEM; - - r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type, - client->arp_type, optlen, &optoffset); - if (r < 0) - return r; - - /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers - refuse to issue an DHCP lease if 'secs' is set to zero */ - r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); - if (r < 0) - return r; - assert(time_now >= client->start_time); - - /* seconds between sending first and last DISCOVER - * must always be strictly positive to deal with broken servers */ - secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1; - packet->dhcp.secs = htobe16(secs); - - /* RFC2132 section 4.1 - A client that cannot receive unicast IP datagrams until its protocol - software has been configured with an IP address SHOULD set the - BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or - DHCPREQUEST messages that client sends. The BROADCAST bit will - provide a hint to the DHCP server and BOOTP relay agent to broadcast - any messages to the client on the client's subnet. - - Note: some interfaces needs this to be enabled, but some networks - needs this to be disabled as broadcasts are filteretd, so this - needs to be configurable */ - if (client->request_broadcast || client->arp_type != ARPHRD_ETHER) - packet->dhcp.flags = htobe16(0x8000); - - /* RFC2132 section 4.1.1: - The client MUST include its hardware address in the ’chaddr’ field, if - necessary for delivery of DHCP reply messages. Non-Ethernet - interfaces will leave 'chaddr' empty and use the client identifier - instead (eg, RFC 4390 section 2.1). - */ - if (client->arp_type == ARPHRD_ETHER) - memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN); - - /* If no client identifier exists, construct one from an ethernet - address if present */ - if (client->client_id_len == 0 && client->arp_type == ARPHRD_ETHER) { - client->client_id.eth.type = ARPHRD_ETHER; - memcpy(&client->client_id.eth.haddr, &client->mac_addr, ETH_ALEN); - client->client_id_len = sizeof (client->client_id.eth); - } - - /* Some DHCP servers will refuse to issue an DHCP lease if the Client - Identifier option is not set */ - if (client->client_id_len) { - r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_CLIENT_IDENTIFIER, - client->client_id_len, - &client->client_id.raw); - if (r < 0) - return r; - } - - /* RFC2131 section 3.5: - in its initial DHCPDISCOVER or DHCPREQUEST message, a - client may provide the server with a list of specific - parameters the client is interested in. If the client - includes a list of parameters in a DHCPDISCOVER message, - it MUST include that list in any subsequent DHCPREQUEST - messages. - */ - r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_PARAMETER_REQUEST_LIST, - client->req_opts_size, client->req_opts); - if (r < 0) - return r; - - /* RFC2131 section 3.5: - The client SHOULD include the ’maximum DHCP message size’ option to - let the server know how large the server may make its DHCP messages. - - Note (from ConnMan): Some DHCP servers will send bigger DHCP packets - than the defined default size unless the Maximum Messge Size option - is explicitely set - - RFC3442 "Requirements to Avoid Sizing Constraints": - Because a full routing table can be quite large, the standard 576 - octet maximum size for a DHCP message may be too short to contain - some legitimate Classless Static Route options. Because of this, - clients implementing the Classless Static Route option SHOULD send a - Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP - stack is capable of receiving larger IP datagrams. In this case, the - client SHOULD set the value of this option to at least the MTU of the - interface that the client is configuring. The client MAY set the - value of this option higher, up to the size of the largest UDP packet - it is prepared to accept. (Note that the value specified in the - Maximum DHCP Message Size option is the total maximum packet size, - including IP and UDP headers.) - */ - max_size = htobe16(size); - r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0, - DHCP_OPTION_MAXIMUM_MESSAGE_SIZE, - 2, &max_size); - if (r < 0) - return r; - - *_optlen = optlen; - *_optoffset = optoffset; - *ret = packet; - packet = NULL; - - return 0; -} - -static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet, - size_t len) { - dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT, - INADDR_BROADCAST, DHCP_PORT_SERVER, len); - - return dhcp_network_send_raw_socket(client->fd, &client->link, - packet, len); -} - -static int client_send_discover(sd_dhcp_client *client) { - _cleanup_free_ DHCPPacket *discover = NULL; - size_t optoffset, optlen; - int r; - - assert(client); - assert(client->state == DHCP_STATE_INIT || - client->state == DHCP_STATE_SELECTING); - - r = client_message_init(client, &discover, DHCP_DISCOVER, - &optlen, &optoffset); - if (r < 0) - return r; - - /* the client may suggest values for the network address - and lease time in the DHCPDISCOVER message. The client may include - the ’requested IP address’ option to suggest that a particular IP - address be assigned, and may include the ’IP address lease time’ - option to suggest the lease time it would like. - */ - if (client->last_addr != INADDR_ANY) { - r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_REQUESTED_IP_ADDRESS, - 4, &client->last_addr); - if (r < 0) - return r; - } - - /* it is unclear from RFC 2131 if client should send hostname in - DHCPDISCOVER but dhclient does and so we do as well - */ - if (client->hostname) { - r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_HOST_NAME, - strlen(client->hostname), client->hostname); - if (r < 0) - return r; - } - - if (client->vendor_class_identifier) { - r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_VENDOR_CLASS_IDENTIFIER, - strlen(client->vendor_class_identifier), - client->vendor_class_identifier); - if (r < 0) - return r; - } - - r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - /* We currently ignore: - The client SHOULD wait a random time between one and ten seconds to - desynchronize the use of DHCP at startup. - */ - r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset); - if (r < 0) - return r; - - log_dhcp_client(client, "DISCOVER"); - - return 0; -} - -static int client_send_request(sd_dhcp_client *client) { - _cleanup_free_ DHCPPacket *request = NULL; - size_t optoffset, optlen; - int r; - - r = client_message_init(client, &request, DHCP_REQUEST, - &optlen, &optoffset); - if (r < 0) - return r; - - switch (client->state) { - /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC, - SELECTING should be REQUESTING) - */ - - case DHCP_STATE_REQUESTING: - /* Client inserts the address of the selected server in ’server - identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be - filled in with the yiaddr value from the chosen DHCPOFFER. - */ - - r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_SERVER_IDENTIFIER, - 4, &client->lease->server_address); - if (r < 0) - return r; - - r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_REQUESTED_IP_ADDRESS, - 4, &client->lease->address); - if (r < 0) - return r; - - break; - - case DHCP_STATE_INIT_REBOOT: - /* ’server identifier’ MUST NOT be filled in, ’requested IP address’ - option MUST be filled in with client’s notion of its previously - assigned address. ’ciaddr’ MUST be zero. - */ - r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_REQUESTED_IP_ADDRESS, - 4, &client->last_addr); - if (r < 0) - return r; - break; - - case DHCP_STATE_RENEWING: - /* ’server identifier’ MUST NOT be filled in, ’requested IP address’ - option MUST NOT be filled in, ’ciaddr’ MUST be filled in with - client’s IP address. - */ - - /* fall through */ - case DHCP_STATE_REBINDING: - /* ’server identifier’ MUST NOT be filled in, ’requested IP address’ - option MUST NOT be filled in, ’ciaddr’ MUST be filled in with - client’s IP address. - - This message MUST be broadcast to the 0xffffffff IP broadcast address. - */ - request->dhcp.ciaddr = client->lease->address; - - break; - - case DHCP_STATE_INIT: - case DHCP_STATE_SELECTING: - case DHCP_STATE_REBOOTING: - case DHCP_STATE_BOUND: - case DHCP_STATE_STOPPED: - return -EINVAL; - } - - if (client->hostname) { - r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_HOST_NAME, - strlen(client->hostname), client->hostname); - if (r < 0) - return r; - } - - r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - if (client->state == DHCP_STATE_RENEWING) { - r = dhcp_network_send_udp_socket(client->fd, - client->lease->server_address, - DHCP_PORT_SERVER, - &request->dhcp, - sizeof(DHCPMessage) + optoffset); - } else { - r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset); - } - if (r < 0) - return r; - - switch (client->state) { - case DHCP_STATE_REQUESTING: - log_dhcp_client(client, "REQUEST (requesting)"); - break; - case DHCP_STATE_INIT_REBOOT: - log_dhcp_client(client, "REQUEST (init-reboot)"); - break; - case DHCP_STATE_RENEWING: - log_dhcp_client(client, "REQUEST (renewing)"); - break; - case DHCP_STATE_REBINDING: - log_dhcp_client(client, "REQUEST (rebinding)"); - break; - default: - log_dhcp_client(client, "REQUEST (invalid)"); - break; - } - - return 0; -} - -static int client_start(sd_dhcp_client *client); - -static int client_timeout_resend(sd_event_source *s, uint64_t usec, - void *userdata) { - sd_dhcp_client *client = userdata; - DHCP_CLIENT_DONT_DESTROY(client); - usec_t next_timeout = 0; - uint64_t time_now; - uint32_t time_left; - int r; - - assert(s); - assert(client); - assert(client->event); - - r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); - if (r < 0) - goto error; - - switch (client->state) { - case DHCP_STATE_RENEWING: - - time_left = (client->lease->t2 - client->lease->t1) / 2; - if (time_left < 60) - time_left = 60; - - next_timeout = time_now + time_left * USEC_PER_SEC; - - break; - - case DHCP_STATE_REBINDING: - - time_left = (client->lease->lifetime - client->lease->t2) / 2; - if (time_left < 60) - time_left = 60; - - next_timeout = time_now + time_left * USEC_PER_SEC; - break; - - case DHCP_STATE_REBOOTING: - /* start over as we did not receive a timely ack or nak */ - r = client_initialize(client); - if (r < 0) - goto error; - - r = client_start(client); - if (r < 0) - goto error; - else { - log_dhcp_client(client, "REBOOTED"); - return 0; - } - - case DHCP_STATE_INIT: - case DHCP_STATE_INIT_REBOOT: - case DHCP_STATE_SELECTING: - case DHCP_STATE_REQUESTING: - case DHCP_STATE_BOUND: - - if (client->attempt < 64) - client->attempt *= 2; - - next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC; - - break; - - case DHCP_STATE_STOPPED: - r = -EINVAL; - goto error; - } - - next_timeout += (random_u32() & 0x1fffff); - - client->timeout_resend = sd_event_source_unref(client->timeout_resend); - - r = sd_event_add_time(client->event, - &client->timeout_resend, - clock_boottime_or_monotonic(), - next_timeout, 10 * USEC_PER_MSEC, - client_timeout_resend, client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->timeout_resend, - client->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); - if (r < 0) - goto error; - - switch (client->state) { - case DHCP_STATE_INIT: - r = client_send_discover(client); - if (r >= 0) { - client->state = DHCP_STATE_SELECTING; - client->attempt = 1; - } else { - if (client->attempt >= 64) - goto error; - } - - break; - - case DHCP_STATE_SELECTING: - r = client_send_discover(client); - if (r < 0 && client->attempt >= 64) - goto error; - - break; - - case DHCP_STATE_INIT_REBOOT: - case DHCP_STATE_REQUESTING: - case DHCP_STATE_RENEWING: - case DHCP_STATE_REBINDING: - r = client_send_request(client); - if (r < 0 && client->attempt >= 64) - goto error; - - if (client->state == DHCP_STATE_INIT_REBOOT) - client->state = DHCP_STATE_REBOOTING; - - client->request_sent = time_now; - - break; - - case DHCP_STATE_REBOOTING: - case DHCP_STATE_BOUND: - - break; - - case DHCP_STATE_STOPPED: - r = -EINVAL; - goto error; - } - - return 0; - -error: - client_stop(client, r); - - /* Errors were dealt with when stopping the client, don't spill - errors into the event loop handler */ - return 0; -} - -static int client_initialize_io_events(sd_dhcp_client *client, - sd_event_io_handler_t io_callback) { - int r; - - assert(client); - assert(client->event); - - r = sd_event_add_io(client->event, &client->receive_message, - client->fd, EPOLLIN, io_callback, - client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->receive_message, - client->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message"); - if (r < 0) - goto error; - -error: - if (r < 0) - client_stop(client, r); - - return 0; -} - -static int client_initialize_time_events(sd_dhcp_client *client) { - int r; - - assert(client); - assert(client->event); - - client->timeout_resend = sd_event_source_unref(client->timeout_resend); - - r = sd_event_add_time(client->event, - &client->timeout_resend, - clock_boottime_or_monotonic(), - 0, 0, - client_timeout_resend, client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->timeout_resend, - client->event_priority); - - r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); - if (r < 0) - goto error; - -error: - if (r < 0) - client_stop(client, r); - - return 0; - -} - -static int client_initialize_events(sd_dhcp_client *client, - sd_event_io_handler_t io_callback) { - client_initialize_io_events(client, io_callback); - client_initialize_time_events(client); - - return 0; -} - -static int client_start(sd_dhcp_client *client) { - int r; - - assert_return(client, -EINVAL); - assert_return(client->event, -EINVAL); - assert_return(client->index > 0, -EINVAL); - assert_return(client->fd < 0, -EBUSY); - assert_return(client->xid == 0, -EINVAL); - assert_return(client->state == DHCP_STATE_INIT || - client->state == DHCP_STATE_INIT_REBOOT, -EBUSY); - - client->xid = random_u32(); - - r = dhcp_network_bind_raw_socket(client->index, &client->link, - client->xid, client->mac_addr, - client->mac_addr_len, client->arp_type); - if (r < 0) { - client_stop(client, r); - return r; - } - client->fd = r; - - if (client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_INIT_REBOOT) - client->start_time = now(clock_boottime_or_monotonic()); - - return client_initialize_events(client, client_receive_message_raw); -} - -static int client_timeout_expire(sd_event_source *s, uint64_t usec, - void *userdata) { - sd_dhcp_client *client = userdata; - DHCP_CLIENT_DONT_DESTROY(client); - - log_dhcp_client(client, "EXPIRED"); - - client_notify(client, DHCP_EVENT_EXPIRED); - - /* lease was lost, start over if not freed or stopped in callback */ - if (client->state != DHCP_STATE_STOPPED) { - client_initialize(client); - client_start(client); - } - - return 0; -} - -static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) { - sd_dhcp_client *client = userdata; - DHCP_CLIENT_DONT_DESTROY(client); - int r; - - client->receive_message = sd_event_source_unref(client->receive_message); - client->fd = asynchronous_close(client->fd); - - client->state = DHCP_STATE_REBINDING; - client->attempt = 1; - - r = dhcp_network_bind_raw_socket(client->index, &client->link, - client->xid, client->mac_addr, - client->mac_addr_len, client->arp_type); - if (r < 0) { - client_stop(client, r); - return 0; - } - client->fd = r; - - return client_initialize_events(client, client_receive_message_raw); -} - -static int client_timeout_t1(sd_event_source *s, uint64_t usec, - void *userdata) { - sd_dhcp_client *client = userdata; - DHCP_CLIENT_DONT_DESTROY(client); - - client->state = DHCP_STATE_RENEWING; - client->attempt = 1; - - return client_initialize_time_events(client); -} - -static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, - size_t len) { - _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; - int r; - - r = dhcp_lease_new(&lease); - if (r < 0) - return r; - - if (client->client_id_len) { - r = dhcp_lease_set_client_id(lease, - (uint8_t *) &client->client_id.raw, - client->client_id_len); - if (r < 0) - return r; - } - - r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease); - if (r != DHCP_OFFER) { - log_dhcp_client(client, "received message was not an OFFER, ignoring"); - return -ENOMSG; - } - - lease->next_server = offer->siaddr; - - lease->address = offer->yiaddr; - - if (lease->address == INADDR_ANY || - lease->server_address == INADDR_ANY || - lease->lifetime == 0) { - log_dhcp_client(client, "received lease lacks address, server " - "address or lease lifetime, ignoring"); - return -ENOMSG; - } - - if (lease->subnet_mask == INADDR_ANY) { - r = dhcp_lease_set_default_subnet_mask(lease); - if (r < 0) { - log_dhcp_client(client, "received lease lacks subnet " - "mask, and a fallback one can not be " - "generated, ignoring"); - return -ENOMSG; - } - } - - sd_dhcp_lease_unref(client->lease); - client->lease = lease; - lease = NULL; - - log_dhcp_client(client, "OFFER"); - - return 0; -} - -static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, - size_t len) { - int r; - - r = dhcp_option_parse(force, len, NULL, NULL); - if (r != DHCP_FORCERENEW) - return -ENOMSG; - - log_dhcp_client(client, "FORCERENEW"); - - return 0; -} - -static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, - size_t len) { - _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; - int r; - - r = dhcp_lease_new(&lease); - if (r < 0) - return r; - - if (client->client_id_len) { - r = dhcp_lease_set_client_id(lease, - (uint8_t *) &client->client_id.raw, - client->client_id_len); - if (r < 0) - return r; - } - - r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease); - if (r == DHCP_NAK) { - log_dhcp_client(client, "NAK"); - return -EADDRNOTAVAIL; - } - - if (r != DHCP_ACK) { - log_dhcp_client(client, "received message was not an ACK, ignoring"); - return -ENOMSG; - } - - lease->next_server = ack->siaddr; - - lease->address = ack->yiaddr; - - if (lease->address == INADDR_ANY || - lease->server_address == INADDR_ANY || - lease->lifetime == 0) { - log_dhcp_client(client, "received lease lacks address, server " - "address or lease lifetime, ignoring"); - return -ENOMSG; - } - - if (lease->subnet_mask == INADDR_ANY) { - r = dhcp_lease_set_default_subnet_mask(lease); - if (r < 0) { - log_dhcp_client(client, "received lease lacks subnet " - "mask, and a fallback one can not be " - "generated, ignoring"); - return -ENOMSG; - } - } - - r = DHCP_EVENT_IP_ACQUIRE; - if (client->lease) { - if (client->lease->address != lease->address || - client->lease->subnet_mask != lease->subnet_mask || - client->lease->router != lease->router) { - r = DHCP_EVENT_IP_CHANGE; - } else - r = DHCP_EVENT_RENEW; - - client->lease = sd_dhcp_lease_unref(client->lease); - } - - client->lease = lease; - lease = NULL; - - log_dhcp_client(client, "ACK"); - - return r; -} - -static uint64_t client_compute_timeout(sd_dhcp_client *client, - uint32_t lifetime, double factor) { - assert(client); - assert(client->request_sent); - assert(lifetime); - - return client->request_sent + ((lifetime - 3) * USEC_PER_SEC * factor) + - + (random_u32() & 0x1fffff); -} - -static int client_set_lease_timeouts(sd_dhcp_client *client) { - usec_t time_now; - uint64_t lifetime_timeout; - uint64_t t2_timeout; - uint64_t t1_timeout; - char time_string[FORMAT_TIMESPAN_MAX]; - int r; - - assert(client); - assert(client->event); - assert(client->lease); - assert(client->lease->lifetime); - - client->timeout_t1 = sd_event_source_unref(client->timeout_t1); - client->timeout_t2 = sd_event_source_unref(client->timeout_t2); - client->timeout_expire = sd_event_source_unref(client->timeout_expire); - - /* don't set timers for infinite leases */ - if (client->lease->lifetime == 0xffffffff) - return 0; - - r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); - if (r < 0) - return r; - assert(client->request_sent <= time_now); - - /* convert the various timeouts from relative (secs) to absolute (usecs) */ - lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1); - if (client->lease->t1 && client->lease->t2) { - /* both T1 and T2 are given */ - if (client->lease->t1 < client->lease->t2 && - client->lease->t2 < client->lease->lifetime) { - /* they are both valid */ - t2_timeout = client_compute_timeout(client, client->lease->t2, 1); - t1_timeout = client_compute_timeout(client, client->lease->t1, 1); - } else { - /* discard both */ - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t1 = client->lease->lifetime / 2; - } - } else if (client->lease->t2 && client->lease->t2 < client->lease->lifetime) { - /* only T2 is given, and it is valid */ - t2_timeout = client_compute_timeout(client, client->lease->t2, 1); - t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t1 = client->lease->lifetime / 2; - if (t2_timeout <= t1_timeout) { - /* the computed T1 would be invalid, so discard T2 */ - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - } - } else if (client->lease->t1 && client->lease->t1 < client->lease->lifetime) { - /* only T1 is given, and it is valid */ - t1_timeout = client_compute_timeout(client, client->lease->t1, 1); - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - if (t2_timeout <= t1_timeout) { - /* the computed T2 would be invalid, so discard T1 */ - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t2 = client->lease->lifetime / 2; - } - } else { - /* fall back to the default timeouts */ - t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t1 = client->lease->lifetime / 2; - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - } - - /* arm lifetime timeout */ - r = sd_event_add_time(client->event, &client->timeout_expire, - clock_boottime_or_monotonic(), - lifetime_timeout, 10 * USEC_PER_MSEC, - client_timeout_expire, client); - if (r < 0) - return r; - - r = sd_event_source_set_priority(client->timeout_expire, - client->event_priority); - if (r < 0) - return r; - - r = sd_event_source_set_description(client->timeout_expire, "dhcp4-lifetime"); - if (r < 0) - return r; - - log_dhcp_client(client, "lease expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - lifetime_timeout - time_now, 0)); - - /* don't arm earlier timeouts if this has already expired */ - if (lifetime_timeout <= time_now) - return 0; - - /* arm T2 timeout */ - r = sd_event_add_time(client->event, - &client->timeout_t2, - clock_boottime_or_monotonic(), - t2_timeout, - 10 * USEC_PER_MSEC, - client_timeout_t2, client); - if (r < 0) - return r; - - r = sd_event_source_set_priority(client->timeout_t2, - client->event_priority); - if (r < 0) - return r; - - r = sd_event_source_set_description(client->timeout_t2, "dhcp4-t2-timeout"); - if (r < 0) - return r; - - log_dhcp_client(client, "T2 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - t2_timeout - time_now, 0)); - - /* don't arm earlier timeout if this has already expired */ - if (t2_timeout <= time_now) - return 0; - - /* arm T1 timeout */ - r = sd_event_add_time(client->event, - &client->timeout_t1, - clock_boottime_or_monotonic(), - t1_timeout, 10 * USEC_PER_MSEC, - client_timeout_t1, client); - if (r < 0) - return r; - - r = sd_event_source_set_priority(client->timeout_t1, - client->event_priority); - if (r < 0) - return r; - - r = sd_event_source_set_description(client->timeout_t1, "dhcp4-t1-timer"); - if (r < 0) - return r; - - log_dhcp_client(client, "T1 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - t1_timeout - time_now, 0)); - - return 0; -} - -static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, - int len) { - DHCP_CLIENT_DONT_DESTROY(client); - int r = 0, notify_event = 0; - - assert(client); - assert(client->event); - assert(message); - - switch (client->state) { - case DHCP_STATE_SELECTING: - - r = client_handle_offer(client, message, len); - if (r >= 0) { - - client->timeout_resend = - sd_event_source_unref(client->timeout_resend); - - client->state = DHCP_STATE_REQUESTING; - client->attempt = 1; - - r = sd_event_add_time(client->event, - &client->timeout_resend, - clock_boottime_or_monotonic(), - 0, 0, - client_timeout_resend, client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->timeout_resend, - client->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); - if (r < 0) - goto error; - } else if (r == -ENOMSG) - /* invalid message, let's ignore it */ - return 0; - - break; - - case DHCP_STATE_REBOOTING: - case DHCP_STATE_REQUESTING: - case DHCP_STATE_RENEWING: - case DHCP_STATE_REBINDING: - - r = client_handle_ack(client, message, len); - if (r >= 0) { - client->timeout_resend = - sd_event_source_unref(client->timeout_resend); - client->receive_message = - sd_event_source_unref(client->receive_message); - client->fd = asynchronous_close(client->fd); - - if (IN_SET(client->state, DHCP_STATE_REQUESTING, - DHCP_STATE_REBOOTING)) - notify_event = DHCP_EVENT_IP_ACQUIRE; - else if (r != DHCP_EVENT_IP_ACQUIRE) - notify_event = r; - - client->state = DHCP_STATE_BOUND; - client->attempt = 1; - - client->last_addr = client->lease->address; - - r = client_set_lease_timeouts(client); - if (r < 0) - goto error; - - r = dhcp_network_bind_udp_socket(client->lease->address, - DHCP_PORT_CLIENT); - if (r < 0) { - log_dhcp_client(client, "could not bind UDP socket"); - goto error; - } - - client->fd = r; - - client_initialize_io_events(client, client_receive_message_udp); - - if (notify_event) { - client_notify(client, notify_event); - if (client->state == DHCP_STATE_STOPPED) - return 0; - } - - } else if (r == -EADDRNOTAVAIL) { - /* got a NAK, let's restart the client */ - client->timeout_resend = - sd_event_source_unref(client->timeout_resend); - - r = client_initialize(client); - if (r < 0) - goto error; - - r = client_start(client); - if (r < 0) - goto error; - - log_dhcp_client(client, "REBOOTED"); - - return 0; - } else if (r == -ENOMSG) - /* invalid message, let's ignore it */ - return 0; - - break; - - case DHCP_STATE_BOUND: - r = client_handle_forcerenew(client, message, len); - if (r >= 0) { - r = client_timeout_t1(NULL, 0, client); - if (r < 0) - goto error; - } else if (r == -ENOMSG) - /* invalid message, let's ignore it */ - return 0; - - break; - - case DHCP_STATE_INIT: - case DHCP_STATE_INIT_REBOOT: - - break; - - case DHCP_STATE_STOPPED: - r = -EINVAL; - goto error; - } - -error: - if (r < 0) - client_stop(client, r); - - return r; -} - -static int client_receive_message_udp(sd_event_source *s, int fd, - uint32_t revents, void *userdata) { - sd_dhcp_client *client = userdata; - _cleanup_free_ DHCPMessage *message = NULL; - int buflen = 0, len, r; - const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } }; - const struct ether_addr *expected_chaddr = NULL; - uint8_t expected_hlen = 0; - - assert(s); - assert(client); - - r = ioctl(fd, FIONREAD, &buflen); - if (r < 0) - return r; - - if (buflen < 0) - /* this can't be right */ - return -EIO; - - message = malloc0(buflen); - if (!message) - return -ENOMEM; - - len = read(fd, message, buflen); - if (len < 0) { - log_dhcp_client(client, "could not receive message from UDP " - "socket: %m"); - return 0; - } else if ((size_t)len < sizeof(DHCPMessage)) { - log_dhcp_client(client, "too small to be a DHCP message: ignoring"); - return 0; - } - - if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) { - log_dhcp_client(client, "not a DHCP message: ignoring"); - return 0; - } - - if (message->op != BOOTREPLY) { - log_dhcp_client(client, "not a BOOTREPLY message: ignoring"); - return 0; - } - - if (message->htype != client->arp_type) { - log_dhcp_client(client, "packet type does not match client type"); - return 0; - } - - if (client->arp_type == ARPHRD_ETHER) { - expected_hlen = ETH_ALEN; - expected_chaddr = (const struct ether_addr *) &client->mac_addr; - } else { - /* Non-ethernet links expect zero chaddr */ - expected_hlen = 0; - expected_chaddr = &zero_mac; - } - - if (message->hlen != expected_hlen) { - log_dhcp_client(client, "unexpected packet hlen %d", message->hlen); - return 0; - } - - if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) { - log_dhcp_client(client, "received chaddr does not match " - "expected: ignoring"); - return 0; - } - - if (client->state != DHCP_STATE_BOUND && - be32toh(message->xid) != client->xid) { - /* in BOUND state, we may receive FORCERENEW with xid set by server, - so ignore the xid in this case */ - log_dhcp_client(client, "received xid (%u) does not match " - "expected (%u): ignoring", - be32toh(message->xid), client->xid); - return 0; - } - - return client_handle_message(client, message, len); -} - -static int client_receive_message_raw(sd_event_source *s, int fd, - uint32_t revents, void *userdata) { - sd_dhcp_client *client = userdata; - _cleanup_free_ DHCPPacket *packet = NULL; - uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))]; - struct iovec iov = {}; - struct msghdr msg = { - .msg_iov = &iov, - .msg_iovlen = 1, - .msg_control = cmsgbuf, - .msg_controllen = sizeof(cmsgbuf), - }; - struct cmsghdr *cmsg; - bool checksum = true; - int buflen = 0, len, r; - - assert(s); - assert(client); - - r = ioctl(fd, FIONREAD, &buflen); - if (r < 0) - return r; - - if (buflen < 0) - /* this can't be right */ - return -EIO; - - packet = malloc0(buflen); - if (!packet) - return -ENOMEM; - - iov.iov_base = packet; - iov.iov_len = buflen; - - len = recvmsg(fd, &msg, 0); - if (len < 0) { - log_dhcp_client(client, "could not receive message from raw " - "socket: %m"); - return 0; - } else if ((size_t)len < sizeof(DHCPPacket)) - return 0; - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level == SOL_PACKET && - cmsg->cmsg_type == PACKET_AUXDATA && - cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) { - struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg); - - checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY); - break; - } - } - - r = dhcp_packet_verify_headers(packet, len, checksum); - if (r < 0) - return 0; - - len -= DHCP_IP_UDP_SIZE; - - return client_handle_message(client, &packet->dhcp, len); -} - -int sd_dhcp_client_start(sd_dhcp_client *client) { - int r; - - assert_return(client, -EINVAL); - - r = client_initialize(client); - if (r < 0) - return r; - - if (client->last_addr) - client->state = DHCP_STATE_INIT_REBOOT; - - r = client_start(client); - if (r >= 0) - log_dhcp_client(client, "STARTED on ifindex %u", client->index); - - return r; -} - -int sd_dhcp_client_stop(sd_dhcp_client *client) { - DHCP_CLIENT_DONT_DESTROY(client); - - assert_return(client, -EINVAL); - - client_stop(client, DHCP_EVENT_STOP); - client->state = DHCP_STATE_STOPPED; - - return 0; -} - -int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, - int priority) { - int r; - - assert_return(client, -EINVAL); - assert_return(!client->event, -EBUSY); - - if (event) - client->event = sd_event_ref(event); - else { - r = sd_event_default(&client->event); - if (r < 0) - return 0; - } - - client->event_priority = priority; - - return 0; -} - -int sd_dhcp_client_detach_event(sd_dhcp_client *client) { - assert_return(client, -EINVAL); - - client->event = sd_event_unref(client->event); - - return 0; -} - -sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) { - if (!client) - return NULL; - - return client->event; -} - -sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) { - if (client) - assert_se(REFCNT_INC(client->n_ref) >= 2); - - return client; -} - -sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) { - if (client && REFCNT_DEC(client->n_ref) <= 0) { - log_dhcp_client(client, "FREE"); - - client_initialize(client); - - client->receive_message = - sd_event_source_unref(client->receive_message); - - sd_dhcp_client_detach_event(client); - - sd_dhcp_lease_unref(client->lease); - - free(client->req_opts); - free(client->hostname); - free(client->vendor_class_identifier); - free(client); - } - - return NULL; -} - -int sd_dhcp_client_new(sd_dhcp_client **ret) { - _cleanup_dhcp_client_unref_ sd_dhcp_client *client = NULL; - - assert_return(ret, -EINVAL); - - client = new0(sd_dhcp_client, 1); - if (!client) - return -ENOMEM; - - client->n_ref = REFCNT_INIT; - client->state = DHCP_STATE_INIT; - client->index = -1; - client->fd = -1; - client->attempt = 1; - client->mtu = DHCP_DEFAULT_MIN_SIZE; - - client->req_opts_size = ELEMENTSOF(default_req_opts); - - client->req_opts = memdup(default_req_opts, client->req_opts_size); - if (!client->req_opts) - return -ENOMEM; - - *ret = client; - client = NULL; - - return 0; -} diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c deleted file mode 100644 index 0b5048a6..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp-lease.c +++ /dev/null @@ -1,917 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. - Copyright (C) 2014 Tom Gundersen - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "config.h" - -#include "nm-sd-adapt.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "util.h" -#include "list.h" -#if 0 /* NM_IGNORED */ -#include "mkdir.h" -#endif -#include "fileio.h" -#include "unaligned.h" -#include "in-addr-util.h" - -#include "dhcp-protocol.h" -#include "dhcp-internal.h" -#include "dhcp-lease-internal.h" -#include "sd-dhcp-lease.h" -#include "sd-dhcp-client.h" -#include "network-internal.h" - -int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - addr->s_addr = lease->address; - - return 0; -} - -int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) { - assert_return(lease, -EINVAL); - assert_return(lease, -EINVAL); - - *lifetime = lease->lifetime; - - return 0; -} - -int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) { - assert_return(lease, -EINVAL); - assert_return(mtu, -EINVAL); - - if (lease->mtu) - *mtu = lease->mtu; - else - return -ENOENT; - - return 0; -} - -int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (lease->dns_size) { - *addr = lease->dns; - return lease->dns_size; - } else - return -ENOENT; - - return 0; -} - -int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (lease->ntp_size) { - *addr = lease->ntp; - return lease->ntp_size; - } else - return -ENOENT; - - return 0; -} - -int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) { - assert_return(lease, -EINVAL); - assert_return(domainname, -EINVAL); - - if (lease->domainname) - *domainname = lease->domainname; - else - return -ENOENT; - - return 0; -} - -int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) { - assert_return(lease, -EINVAL); - assert_return(hostname, -EINVAL); - - if (lease->hostname) - *hostname = lease->hostname; - else - return -ENOENT; - - return 0; -} - -int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) { - assert_return(lease, -EINVAL); - assert_return(root_path, -EINVAL); - - if (lease->root_path) - *root_path = lease->root_path; - else - return -ENOENT; - - return 0; -} - -int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (lease->router != INADDR_ANY) - addr->s_addr = lease->router; - else - return -ENOENT; - - return 0; -} - -int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - addr->s_addr = lease->subnet_mask; - - return 0; -} - -int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - addr->s_addr = lease->server_address; - - return 0; -} - -int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - addr->s_addr = lease->next_server; - - return 0; -} - -int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes) { - - assert_return(lease, -EINVAL); - assert_return(routes, -EINVAL); - - if (lease->static_route_size) { - *routes = lease->static_route; - return lease->static_route_size; - } else - return -ENOENT; - - return 0; -} - -int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, uint8_t **data) { - assert_return(lease, -EINVAL); - assert_return(data, -EINVAL); - - if (lease->vendor_specific) { - *data = lease->vendor_specific; - return lease->vendor_specific_size; - } else - return -ENOENT; - - return 0; -} - -sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) { - if (lease) - assert_se(REFCNT_INC(lease->n_ref) >= 2); - - return lease; -} - -sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) { - if (lease && REFCNT_DEC(lease->n_ref) <= 0) { - free(lease->hostname); - free(lease->domainname); - free(lease->dns); - free(lease->ntp); - free(lease->static_route); - free(lease->client_id); - free(lease); - } - - return NULL; -} - -static void lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) { - assert(option); - assert(ret); - - if (len == 4) { - *ret = unaligned_read_be32((be32_t*) option); - - if (*ret < min) - *ret = min; - } -} - -static void lease_parse_s32(const uint8_t *option, size_t len, int32_t *ret) { - lease_parse_u32(option, len, (uint32_t *)ret, 0); -} - -static void lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) { - assert(option); - assert(ret); - - if (len == 2) { - *ret = unaligned_read_be16((be16_t*) option); - - if (*ret < min) - *ret = min; - } -} - -static void lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) { - assert(option); - assert(ret); - - if (len == 4) - memcpy(ret, option, 4); -} - -static void lease_parse_bool(const uint8_t *option, size_t len, bool *ret) { - assert(option); - assert(ret); - - if (len == 1) - *ret = !!(*option); -} - -static void lease_parse_u8(const uint8_t *option, size_t len, uint8_t *ret, uint8_t min) { - assert(option); - assert(ret); - - if (len == 1) { - *ret = *option; - - if (*ret < min) - *ret = min; - } -} - -static int lease_parse_string(const uint8_t *option, size_t len, char **ret) { - assert(option); - assert(ret); - - if (len >= 1) { - char *string; - - string = strndup((const char *)option, len); - if (!string) - return -errno; - - free(*ret); - *ret = string; - } - - return 0; -} - -static int lease_parse_binary(const uint8_t *option, size_t len, uint8_t **ret) { - assert (option); - assert (ret); - - if (len >= 1) { - uint8_t *data; - - data = memdup(option, len); - if (!data) - return -errno; - - free(*ret); - *ret = data; - } - - return 0; -} - -static int lease_parse_in_addrs_aux(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size, size_t mult) { - assert(option); - assert(ret); - assert(ret_size); - - if (len && !(len % (4 * mult))) { - size_t size; - struct in_addr *addresses; - - size = len / 4; - - addresses = newdup(struct in_addr, option, size); - if (!addresses) - return -ENOMEM; - - free(*ret); - *ret = addresses; - *ret_size = size; - } - - return 0; -} - -static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) { - return lease_parse_in_addrs_aux(option, len, ret, ret_size, 1); -} - -static int lease_parse_in_addrs_pairs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size) { - return lease_parse_in_addrs_aux(option, len, ret, ret_size, 2); -} - -static int lease_parse_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes, - size_t *routes_size, size_t *routes_allocated) { - - struct in_addr addr; - - assert(option); - assert(routes); - assert(routes_size); - assert(routes_allocated); - - if (!len) - return 0; - - if (len % 8 != 0) - return -EINVAL; - - if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8))) - return -ENOMEM; - - while (len >= 8) { - struct sd_dhcp_route *route = *routes + *routes_size; - int r; - - r = in_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen); - if (r < 0) { - log_error("Failed to determine destination prefix length from class based IP, ignoring"); - continue; - } - - lease_parse_be32(option, 4, &addr.s_addr); - route->dst_addr = inet_makeaddr(inet_netof(addr), 0); - option += 4; - - lease_parse_be32(option, 4, &route->gw_addr.s_addr); - option += 4; - - len -= 8; - (*routes_size)++; - } - - return 0; -} - -/* parses RFC3442 Classless Static Route Option */ -static int lease_parse_classless_routes(const uint8_t *option, size_t len, struct sd_dhcp_route **routes, - size_t *routes_size, size_t *routes_allocated) { - - assert(option); - assert(routes); - assert(routes_size); - assert(routes_allocated); - - /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */ - - while (len > 0) { - uint8_t dst_octets; - struct sd_dhcp_route *route; - - if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1)) - return -ENOMEM; - - route = *routes + *routes_size; - - dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1); - route->dst_prefixlen = *option; - option++; - len--; - - /* can't have more than 4 octets in IPv4 */ - if (dst_octets > 4 || len < dst_octets) - return -EINVAL; - - route->dst_addr.s_addr = 0; - memcpy(&route->dst_addr.s_addr, option, dst_octets); - option += dst_octets; - len -= dst_octets; - - if (len < 4) - return -EINVAL; - - lease_parse_be32(option, 4, &route->gw_addr.s_addr); - option += 4; - len -= 4; - - (*routes_size)++; - } - - return 0; -} - -int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option, - void *user_data) { - sd_dhcp_lease *lease = user_data; - int r; - - assert(lease); - - switch(code) { - - case DHCP_OPTION_TIME_OFFSET: - lease_parse_s32(option, len, &lease->time_offset); - - break; - - case DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT: - lease_parse_u32(option, len, &lease->mtu_aging_timeout, 0); - - break; - - case DHCP_OPTION_IP_ADDRESS_LEASE_TIME: - lease_parse_u32(option, len, &lease->lifetime, 1); - - break; - - case DHCP_OPTION_SERVER_IDENTIFIER: - lease_parse_be32(option, len, &lease->server_address); - - break; - - case DHCP_OPTION_SUBNET_MASK: - lease_parse_be32(option, len, &lease->subnet_mask); - - break; - - case DHCP_OPTION_BROADCAST: - lease_parse_be32(option, len, &lease->broadcast); - - break; - - case DHCP_OPTION_ROUTER: - lease_parse_be32(option, len, &lease->router); - - break; - - case DHCP_OPTION_DOMAIN_NAME_SERVER: - r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size); - if (r < 0) - return r; - - break; - - case DHCP_OPTION_NTP_SERVER: - r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size); - if (r < 0) - return r; - - break; - - case DHCP_OPTION_POLICY_FILTER: - r = lease_parse_in_addrs_pairs(option, len, &lease->policy_filter, &lease->policy_filter_size); - if (r < 0) - return r; - - break; - - case DHCP_OPTION_STATIC_ROUTE: - r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, - &lease->static_route_allocated); - if (r < 0) - return r; - - break; - - case DHCP_OPTION_INTERFACE_MTU: - lease_parse_u16(option, len, &lease->mtu, 68); - - break; - - case DHCP_OPTION_INTERFACE_MDR: - lease_parse_u16(option, len, &lease->mdr, 576); - - break; - - case DHCP_OPTION_INTERFACE_TTL: - lease_parse_u8(option, len, &lease->ttl, 1); - - break; - - case DHCP_OPTION_BOOT_FILE_SIZE: - lease_parse_u16(option, len, &lease->boot_file_size, 0); - - break; - - case DHCP_OPTION_DOMAIN_NAME: - { - _cleanup_free_ char *domainname = NULL; - - r = lease_parse_string(option, len, &domainname); - if (r < 0) - return r; - - if (!hostname_is_valid(domainname) || is_localhost(domainname)) - break; - - free(lease->domainname); - lease->domainname = domainname; - domainname = NULL; - - break; - } - case DHCP_OPTION_HOST_NAME: - { - _cleanup_free_ char *hostname = NULL; - - r = lease_parse_string(option, len, &hostname); - if (r < 0) - return r; - - if (!hostname_is_valid(hostname) || is_localhost(hostname)) - break; - - free(lease->hostname); - lease->hostname = hostname; - hostname = NULL; - - break; - } - case DHCP_OPTION_ROOT_PATH: - r = lease_parse_string(option, len, &lease->root_path); - if (r < 0) - return r; - - break; - - case DHCP_OPTION_RENEWAL_T1_TIME: - lease_parse_u32(option, len, &lease->t1, 1); - - break; - - case DHCP_OPTION_REBINDING_T2_TIME: - lease_parse_u32(option, len, &lease->t2, 1); - - break; - - case DHCP_OPTION_ENABLE_IP_FORWARDING: - lease_parse_bool(option, len, &lease->ip_forward); - - break; - - case DHCP_OPTION_ENABLE_IP_FORWARDING_NL: - lease_parse_bool(option, len, &lease->ip_forward_non_local); - - break; - - case DHCP_OPTION_CLASSLESS_STATIC_ROUTE: - r = lease_parse_classless_routes(option, len, &lease->static_route, &lease->static_route_size, - &lease->static_route_allocated); - if (r < 0) - return r; - - break; - - case DHCP_OPTION_VENDOR_SPECIFIC: - r = lease_parse_binary(option, len, &lease->vendor_specific); - if (r < 0) - return r; - lease->vendor_specific_size = len; - - break; - } - - return 0; -} - -int dhcp_lease_new(sd_dhcp_lease **ret) { - sd_dhcp_lease *lease; - - lease = new0(sd_dhcp_lease, 1); - if (!lease) - return -ENOMEM; - - lease->router = INADDR_ANY; - lease->n_ref = REFCNT_INIT; - - *ret = lease; - return 0; -} - -int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { - _cleanup_free_ char *temp_path = NULL; - _cleanup_fclose_ FILE *f = NULL; - struct in_addr address; - const struct in_addr *addresses; - const uint8_t *client_id; - size_t client_id_len; - const char *string; - uint8_t *data; - uint16_t mtu; - struct sd_dhcp_route *routes; - int r; - - assert(lease); - assert(lease_file); - - r = fopen_temporary(lease_file, &f, &temp_path); - if (r < 0) - goto finish; - - fchmod(fileno(f), 0644); - - r = sd_dhcp_lease_get_address(lease, &address); - if (r < 0) - goto finish; - - fprintf(f, - "# This is private data. Do not parse.\n" - "ADDRESS=%s\n", inet_ntoa(address)); - - r = sd_dhcp_lease_get_netmask(lease, &address); - if (r < 0) - goto finish; - - fprintf(f, "NETMASK=%s\n", inet_ntoa(address)); - - r = sd_dhcp_lease_get_router(lease, &address); - if (r >= 0) - fprintf(f, "ROUTER=%s\n", inet_ntoa(address)); - - r = sd_dhcp_lease_get_server_identifier(lease, &address); - if (r >= 0) - fprintf(f, "SERVER_ADDRESS=%s\n", - inet_ntoa(address)); - - r = sd_dhcp_lease_get_next_server(lease, &address); - if (r >= 0) - fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address)); - - r = sd_dhcp_lease_get_mtu(lease, &mtu); - if (r >= 0) - fprintf(f, "MTU=%" PRIu16 "\n", mtu); - - fputs("DNS=", f); - r = sd_dhcp_lease_get_dns(lease, &addresses); - if (r >= 0) - serialize_in_addrs(f, addresses, r); - fputs("\n", f); - - fputs("NTP=", f); - r = sd_dhcp_lease_get_ntp(lease, &addresses); - if (r >= 0) - serialize_in_addrs(f, addresses, r); - fputs("\n", f); - - r = sd_dhcp_lease_get_domainname(lease, &string); - if (r >= 0) - fprintf(f, "DOMAINNAME=%s\n", string); - - r = sd_dhcp_lease_get_hostname(lease, &string); - if (r >= 0) - fprintf(f, "HOSTNAME=%s\n", string); - - r = sd_dhcp_lease_get_root_path(lease, &string); - if (r >= 0) - fprintf(f, "ROOT_PATH=%s\n", string); - - r = sd_dhcp_lease_get_routes(lease, &routes); - if (r >= 0) - serialize_dhcp_routes(f, "ROUTES", routes, r); - - r = sd_dhcp_lease_get_vendor_specific(lease, &data); - if (r >= 0) { - _cleanup_free_ char *option_hex = NULL; - - option_hex = hexmem(data, r); - if (!option_hex) { - r = -ENOMEM; - goto finish; - } - fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex); - } - - r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len); - if (r >= 0) { - _cleanup_free_ char *client_id_hex = NULL; - - client_id_hex = hexmem (client_id, client_id_len); - if (!client_id_hex) { - r = -ENOMEM; - goto finish; - } - fprintf(f, "CLIENTID=%s\n", client_id_hex); - } - - r = 0; - - fflush(f); - - if (ferror(f) || rename(temp_path, lease_file) < 0) { - r = -errno; - unlink(lease_file); - unlink(temp_path); - } - -finish: - if (r < 0) - log_error("Failed to save lease data %s: %s", lease_file, strerror(-r)); - - return r; -} - -int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { - _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; - _cleanup_free_ char *address = NULL, *router = NULL, *netmask = NULL, - *server_address = NULL, *next_server = NULL, - *dns = NULL, *ntp = NULL, *mtu = NULL, - *routes = NULL, *client_id_hex = NULL; - struct in_addr addr; - int r; - - assert(lease_file); - assert(ret); - - r = dhcp_lease_new(&lease); - if (r < 0) - return r; - - r = parse_env_file(lease_file, NEWLINE, - "ADDRESS", &address, - "ROUTER", &router, - "NETMASK", &netmask, - "SERVER_IDENTIFIER", &server_address, - "NEXT_SERVER", &next_server, - "DNS", &dns, - "NTP", &ntp, - "MTU", &mtu, - "DOMAINNAME", &lease->domainname, - "HOSTNAME", &lease->hostname, - "ROOT_PATH", &lease->root_path, - "ROUTES", &routes, - "CLIENTID", &client_id_hex, - NULL); - if (r < 0) { - if (r == -ENOENT) - return 0; - - log_error("Failed to read %s: %s", lease_file, strerror(-r)); - return r; - } - - r = inet_pton(AF_INET, address, &addr); - if (r < 0) - return r; - - lease->address = addr.s_addr; - - if (router) { - r = inet_pton(AF_INET, router, &addr); - if (r < 0) - return r; - - lease->router = addr.s_addr; - } - - r = inet_pton(AF_INET, netmask, &addr); - if (r < 0) - return r; - - lease->subnet_mask = addr.s_addr; - - if (server_address) { - r = inet_pton(AF_INET, server_address, &addr); - if (r < 0) - return r; - - lease->server_address = addr.s_addr; - } - - if (next_server) { - r = inet_pton(AF_INET, next_server, &addr); - if (r < 0) - return r; - - lease->next_server = addr.s_addr; - } - - if (dns) { - r = deserialize_in_addrs(&lease->dns, dns); - if (r < 0) - return r; - - lease->dns_size = r; - } - - if (ntp) { - r = deserialize_in_addrs(&lease->ntp, ntp); - if (r < 0) - return r; - - lease->ntp_size = r; - } - - if (mtu) { - uint16_t u; - if (sscanf(mtu, "%" SCNu16, &u) > 0) - lease->mtu = u; - } - - if (routes) { - r = deserialize_dhcp_routes(&lease->static_route, &lease->static_route_size, - &lease->static_route_allocated, routes); - if (r < 0) - return r; - } - - if (client_id_hex) { - if (strlen (client_id_hex) % 2) - return -EINVAL; - - lease->client_id = unhexmem (client_id_hex, strlen (client_id_hex)); - if (!lease->client_id) - return -ENOMEM; - lease->client_id_len = strlen (client_id_hex) / 2; - } - - *ret = lease; - lease = NULL; - - return 0; -} - -int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) { - struct in_addr address; - struct in_addr mask; - int r; - - assert(lease); - - address.s_addr = lease->address; - - /* fall back to the default subnet masks based on address class */ - r = in_addr_default_subnet_mask(&address, &mask); - if (r < 0) - return r; - - lease->subnet_mask = mask.s_addr; - - return 0; -} - -int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id, - size_t *client_id_len) { - assert_return(lease, -EINVAL); - assert_return(client_id, -EINVAL); - assert_return(client_id_len, -EINVAL); - - *client_id = lease->client_id; - *client_id_len = lease->client_id_len; - return 0; -} - -int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const uint8_t *client_id, - size_t client_id_len) { - assert_return(lease, -EINVAL); - assert_return((!client_id && !client_id_len) || - (client_id && client_id_len), -EINVAL); - - free (lease->client_id); - lease->client_id = NULL; - lease->client_id_len = 0; - - if (client_id) { - lease->client_id = memdup (client_id, client_id_len); - lease->client_id_len = client_id_len; - } - - return 0; -} diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c deleted file mode 100644 index 6754fe19..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-client.c +++ /dev/null @@ -1,1250 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright (C) 2014 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "config.h" - -#include "nm-sd-adapt.h" - -#include -#include -#include -#include - -#if 0 /* NM_IGNORED */ -#include "udev.h" -#include "udev-util.h" -#include "virt.h" -#endif -#include "siphash24.h" -#include "util.h" -#include "refcnt.h" - -#include "network-internal.h" -#include "sd-dhcp6-client.h" -#include "dhcp6-protocol.h" -#include "dhcp6-internal.h" -#include "dhcp6-lease-internal.h" - -#define SYSTEMD_PEN 43793 -#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) - -/* RFC 3315 section 9.1: - * A DUID can be no more than 128 octets long (not including the type code). - */ -#define MAX_DUID_LEN 128 - -#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN - -struct sd_dhcp6_client { - RefCount n_ref; - - enum DHCP6State state; - sd_event *event; - int event_priority; - int index; - uint8_t mac_addr[MAX_MAC_ADDR_LEN]; - size_t mac_addr_len; - uint16_t arp_type; - char ifname[IFNAMSIZ]; - DHCP6IA ia_na; - be32_t transaction_id; - usec_t transaction_start; - struct sd_dhcp6_lease *lease; - int fd; - be16_t *req_opts; - size_t req_opts_allocated; - size_t req_opts_len; - sd_event_source *receive_message; - usec_t retransmit_time; - uint8_t retransmit_count; - sd_event_source *timeout_resend; - sd_event_source *timeout_resend_expire; - sd_dhcp6_client_cb_t cb; - void *userdata; - union { - struct { - uint16_t type; /* DHCP6_DUID_LLT */ - uint16_t htype; - uint32_t time; - uint8_t haddr[0]; - } _packed_ llt; - struct { - uint16_t type; /* DHCP6_DUID_EN */ - uint32_t pen; - uint8_t id[8]; - } _packed_ en; - struct { - uint16_t type; /* DHCP6_DUID_LL */ - uint16_t htype; - uint8_t haddr[0]; - } _packed_ ll; - struct { - uint16_t type; /* DHCP6_DUID_UUID */ - sd_id128_t uuid; - } _packed_ uuid; - struct { - uint16_t type; - uint8_t data[MAX_DUID_LEN]; - } _packed_ raw; - } duid; - size_t duid_len; -}; - -static const uint16_t default_req_opts[] = { - DHCP6_OPTION_DNS_SERVERS, - DHCP6_OPTION_DOMAIN_LIST, - DHCP6_OPTION_NTP_SERVER, -}; - -const char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = { - [DHCP6_SOLICIT] = "SOLICIT", - [DHCP6_ADVERTISE] = "ADVERTISE", - [DHCP6_REQUEST] = "REQUEST", - [DHCP6_CONFIRM] = "CONFIRM", - [DHCP6_RENEW] = "RENEW", - [DHCP6_REBIND] = "REBIND", - [DHCP6_REPLY] = "REPLY", - [DHCP6_RELEASE] = "RELEASE", - [DHCP6_DECLINE] = "DECLINE", - [DHCP6_RECONFIGURE] = "RECONFIGURE", - [DHCP6_INFORMATION_REQUEST] = "INFORMATION-REQUEST", - [DHCP6_RELAY_FORW] = "RELAY-FORW", - [DHCP6_RELAY_REPL] = "RELAY-REPL", -}; - -DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type, int); - -const char * dhcp6_message_status_table[_DHCP6_STATUS_MAX] = { - [DHCP6_STATUS_SUCCESS] = "Success", - [DHCP6_STATUS_UNSPEC_FAIL] = "Unspecified failure", - [DHCP6_STATUS_NO_ADDRS_AVAIL] = "No addresses available", - [DHCP6_STATUS_NO_BINDING] = "Binding unavailable", - [DHCP6_STATUS_NOT_ON_LINK] = "Not on link", - [DHCP6_STATUS_USE_MULTICAST] = "Use multicast", -}; - -DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int); - -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_client*, sd_dhcp6_client_unref); -#define _cleanup_dhcp6_client_unref_ _cleanup_(sd_dhcp6_client_unrefp) - -#define DHCP6_CLIENT_DONT_DESTROY(client) \ - _cleanup_dhcp6_client_unref_ _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client) - -static int client_start(sd_dhcp6_client *client, enum DHCP6State state); - -int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, - sd_dhcp6_client_cb_t cb, void *userdata) -{ - assert_return(client, -EINVAL); - - client->cb = cb; - client->userdata = userdata; - - return 0; -} - -int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) -{ - assert_return(client, -EINVAL); - assert_return(interface_index >= -1, -EINVAL); - - client->index = interface_index; - - return 0; -} - -int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, - size_t addr_len, uint16_t arp_type) -{ - assert_return(client, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL); - assert_return(arp_type > 0, -EINVAL); - - if (arp_type == ARPHRD_ETHER) - assert_return(addr_len == ETH_ALEN, -EINVAL); - else if (arp_type == ARPHRD_INFINIBAND) - assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); - else - return -EINVAL; - - if (client->mac_addr_len == addr_len && - memcmp(&client->mac_addr, addr, addr_len) == 0) - return 0; - - memcpy(&client->mac_addr, addr, addr_len); - client->mac_addr_len = addr_len; - client->arp_type = arp_type; - - return 0; -} - -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, - size_t duid_len) -{ - assert_return(client, -EINVAL); - assert_return(duid, -EINVAL); - assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); - - switch (type) { - case DHCP6_DUID_LLT: - if (duid_len <= sizeof(client->duid.llt) - 2) - return -EINVAL; - break; - case DHCP6_DUID_EN: - if (duid_len != sizeof(client->duid.en) - 2) - return -EINVAL; - break; - case DHCP6_DUID_LL: - if (duid_len <= sizeof(client->duid.ll) - 2) - return -EINVAL; - break; - case DHCP6_DUID_UUID: - if (duid_len != sizeof(client->duid.uuid) - 2) - return -EINVAL; - break; - default: - /* accept unknown type in order to be forward compatible */ - break; - } - - client->duid.raw.type = htobe16(type); - memcpy(&client->duid.raw.data, duid, duid_len); - client->duid_len = duid_len + 2; /* +2 for sizeof(type) */ - - return 0; -} - -int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, - uint16_t option) { - size_t t; - - assert_return(client, -EINVAL); - assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY); - - switch(option) { - case DHCP6_OPTION_DNS_SERVERS: - case DHCP6_OPTION_DOMAIN_LIST: - case DHCP6_OPTION_SNTP_SERVERS: - case DHCP6_OPTION_NTP_SERVER: - break; - - default: - return -EINVAL; - } - - for (t = 0; t < client->req_opts_len; t++) - if (client->req_opts[t] == htobe16(option)) - return -EEXIST; - - if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated, - client->req_opts_len + 1)) - return -ENOMEM; - - client->req_opts[client->req_opts_len++] = htobe16(option); - - return 0; -} - -int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) { - assert_return(client, -EINVAL); - assert_return(ret, -EINVAL); - - if (!client->lease) - return -ENOMSG; - - *ret = sd_dhcp6_lease_ref(client->lease); - - return 0; -} - -static void client_notify(sd_dhcp6_client *client, int event) { - if (client->cb) - client->cb(client, event, client->userdata); -} - -static int client_reset(sd_dhcp6_client *client) { - assert_return(client, -EINVAL); - - if (client->lease) { - dhcp6_lease_clear_timers(&client->lease->ia); - client->lease = sd_dhcp6_lease_unref(client->lease); - } - - client->receive_message = - sd_event_source_unref(client->receive_message); - - client->fd = safe_close(client->fd); - - client->transaction_id = 0; - client->transaction_start = 0; - - client->ia_na.timeout_t1 = - sd_event_source_unref(client->ia_na.timeout_t1); - client->ia_na.timeout_t2 = - sd_event_source_unref(client->ia_na.timeout_t2); - - client->retransmit_time = 0; - client->retransmit_count = 0; - client->timeout_resend = sd_event_source_unref(client->timeout_resend); - client->timeout_resend_expire = - sd_event_source_unref(client->timeout_resend_expire); - - client->state = DHCP6_STATE_STOPPED; - - return 0; -} - -static void client_stop(sd_dhcp6_client *client, int error) { - DHCP6_CLIENT_DONT_DESTROY(client); - - assert(client); - - client_notify(client, error); - - client_reset(client); -} - -static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { - _cleanup_free_ DHCP6Message *message = NULL; - struct in6_addr all_servers = - IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT; - size_t len, optlen = 512; - uint8_t *opt; - int r; - usec_t elapsed_usec; - be16_t elapsed_time; - - len = sizeof(DHCP6Message) + optlen; - - message = malloc0(len); - if (!message) - return -ENOMEM; - - opt = (uint8_t *)(message + 1); - - message->transaction_id = client->transaction_id; - - switch(client->state) { - case DHCP6_STATE_SOLICITATION: - message->type = DHCP6_SOLICIT; - - r = dhcp6_option_append(&opt, &optlen, - DHCP6_OPTION_RAPID_COMMIT, 0, NULL); - if (r < 0) - return r; - - r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na); - if (r < 0) - return r; - - break; - - case DHCP6_STATE_REQUEST: - case DHCP6_STATE_RENEW: - - if (client->state == DHCP6_STATE_REQUEST) - message->type = DHCP6_REQUEST; - else - message->type = DHCP6_RENEW; - - r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_SERVERID, - client->lease->serverid_len, - client->lease->serverid); - if (r < 0) - return r; - - r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia); - if (r < 0) - return r; - - break; - - case DHCP6_STATE_REBIND: - message->type = DHCP6_REBIND; - - r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia); - if (r < 0) - return r; - - break; - - case DHCP6_STATE_STOPPED: - case DHCP6_STATE_BOUND: - return -EINVAL; - } - - r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ORO, - client->req_opts_len * sizeof(be16_t), - client->req_opts); - if (r < 0) - return r; - - r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID, - client->duid_len, &client->duid); - if (r < 0) - return r; - - elapsed_usec = time_now - client->transaction_start; - if (elapsed_usec < 0xffff * USEC_PER_MSEC * 10) - elapsed_time = htobe16(elapsed_usec / USEC_PER_MSEC / 10); - else - elapsed_time = 0xffff; - - r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ELAPSED_TIME, - sizeof(elapsed_time), &elapsed_time); - if (r < 0) - return r; - - r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message, - len - optlen); - if (r < 0) - return r; - - log_dhcp6_client(client, "Sent %s", - dhcp6_message_type_to_string(message->type)); - - return 0; -} - -static int client_timeout_t2(sd_event_source *s, uint64_t usec, - void *userdata) { - sd_dhcp6_client *client = userdata; - - assert_return(s, -EINVAL); - assert_return(client, -EINVAL); - assert_return(client->lease, -EINVAL); - - client->lease->ia.timeout_t2 = - sd_event_source_unref(client->lease->ia.timeout_t2); - - log_dhcp6_client(client, "Timeout T2"); - - client_start(client, DHCP6_STATE_REBIND); - - return 0; -} - -static int client_timeout_t1(sd_event_source *s, uint64_t usec, - void *userdata) { - sd_dhcp6_client *client = userdata; - - assert_return(s, -EINVAL); - assert_return(client, -EINVAL); - assert_return(client->lease, -EINVAL); - - client->lease->ia.timeout_t1 = - sd_event_source_unref(client->lease->ia.timeout_t1); - - log_dhcp6_client(client, "Timeout T1"); - - client_start(client, DHCP6_STATE_RENEW); - - return 0; -} - -static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, - void *userdata) { - sd_dhcp6_client *client = userdata; - DHCP6_CLIENT_DONT_DESTROY(client); - enum DHCP6State state; - - assert(s); - assert(client); - assert(client->event); - - state = client->state; - - client_stop(client, DHCP6_EVENT_RESEND_EXPIRE); - - /* RFC 3315, section 18.1.4., says that "...the client may choose to - use a Solicit message to locate a new DHCP server..." */ - if (state == DHCP6_STATE_REBIND) - client_start(client, DHCP6_STATE_SOLICITATION); - - return 0; -} - -static usec_t client_timeout_compute_random(usec_t val) { - return val - val / 10 + - (random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC; -} - -static int client_timeout_resend(sd_event_source *s, uint64_t usec, - void *userdata) { - int r = 0; - sd_dhcp6_client *client = userdata; - usec_t time_now, init_retransmit_time = 0, max_retransmit_time = 0; - usec_t max_retransmit_duration = 0; - uint8_t max_retransmit_count = 0; - char time_string[FORMAT_TIMESPAN_MAX]; - uint32_t expire = 0; - - assert(s); - assert(client); - assert(client->event); - - client->timeout_resend = sd_event_source_unref(client->timeout_resend); - - switch (client->state) { - case DHCP6_STATE_SOLICITATION: - - if (client->retransmit_count && client->lease) { - client_start(client, DHCP6_STATE_REQUEST); - return 0; - } - - init_retransmit_time = DHCP6_SOL_TIMEOUT; - max_retransmit_time = DHCP6_SOL_MAX_RT; - - break; - - case DHCP6_STATE_REQUEST: - init_retransmit_time = DHCP6_REQ_TIMEOUT; - max_retransmit_time = DHCP6_REQ_MAX_RT; - max_retransmit_count = DHCP6_REQ_MAX_RC; - - break; - - case DHCP6_STATE_RENEW: - init_retransmit_time = DHCP6_REN_TIMEOUT; - max_retransmit_time = DHCP6_REN_MAX_RT; - - /* RFC 3315, section 18.1.3. says max retransmit duration will - be the remaining time until T2. Instead of setting MRD, - wait for T2 to trigger with the same end result */ - - break; - - case DHCP6_STATE_REBIND: - init_retransmit_time = DHCP6_REB_TIMEOUT; - max_retransmit_time = DHCP6_REB_MAX_RT; - - if (!client->timeout_resend_expire) { - r = dhcp6_lease_ia_rebind_expire(&client->lease->ia, - &expire); - if (r < 0) { - client_stop(client, r); - return 0; - } - max_retransmit_duration = expire * USEC_PER_SEC; - } - - break; - - case DHCP6_STATE_STOPPED: - case DHCP6_STATE_BOUND: - return 0; - } - - if (max_retransmit_count && - client->retransmit_count >= max_retransmit_count) { - client_stop(client, DHCP6_EVENT_RETRANS_MAX); - return 0; - } - - r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); - if (r < 0) - goto error; - - r = client_send_message(client, time_now); - if (r >= 0) - client->retransmit_count++; - - if (!client->retransmit_time) { - client->retransmit_time = - client_timeout_compute_random(init_retransmit_time); - - if (client->state == DHCP6_STATE_SOLICITATION) - client->retransmit_time += init_retransmit_time / 10; - - } else { - if (max_retransmit_time && - client->retransmit_time > max_retransmit_time / 2) - client->retransmit_time = client_timeout_compute_random(max_retransmit_time); - else - client->retransmit_time += client_timeout_compute_random(client->retransmit_time); - } - - log_dhcp6_client(client, "Next retransmission in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, - client->retransmit_time, 0)); - - r = sd_event_add_time(client->event, &client->timeout_resend, - clock_boottime_or_monotonic(), - time_now + client->retransmit_time, - 10 * USEC_PER_MSEC, client_timeout_resend, - client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->timeout_resend, - client->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timer"); - if (r < 0) - goto error; - - if (max_retransmit_duration && !client->timeout_resend_expire) { - - log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs", - max_retransmit_duration / USEC_PER_SEC); - - r = sd_event_add_time(client->event, - &client->timeout_resend_expire, - clock_boottime_or_monotonic(), - time_now + max_retransmit_duration, - USEC_PER_SEC, - client_timeout_resend_expire, client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->timeout_resend_expire, - client->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(client->timeout_resend_expire, "dhcp6-resend-expire-timer"); - if (r < 0) - goto error; - } - -error: - if (r < 0) - client_stop(client, r); - - return 0; -} - -static int client_ensure_iaid(sd_dhcp6_client *client) { - const char *name; - uint64_t id; - - assert(client); - - if (client->ia_na.id) - return 0; - - name = client->ifname; - if (name) - siphash24((uint8_t*)&id, name, strlen(name), HASH_KEY.bytes); - else - /* fall back to mac address if no predictable name available */ - siphash24((uint8_t*)&id, &client->mac_addr, - client->mac_addr_len, HASH_KEY.bytes); - - /* fold into 32 bits */ - client->ia_na.id = (id & 0xffffffff) ^ (id >> 32); - - return 0; -} - -static int client_parse_message(sd_dhcp6_client *client, - DHCP6Message *message, size_t len, - sd_dhcp6_lease *lease) { - int r; - uint8_t *optval, *option, *id = NULL; - uint16_t optcode, status; - size_t optlen, id_len; - bool clientid = false; - be32_t iaid_lease; - - option = (uint8_t *)message + sizeof(DHCP6Message); - len -= sizeof(DHCP6Message); - - while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen, - &optval)) >= 0) { - switch (optcode) { - case DHCP6_OPTION_CLIENTID: - if (clientid) { - log_dhcp6_client(client, "%s contains multiple clientids", - dhcp6_message_type_to_string(message->type)); - return -EINVAL; - } - - if (optlen != client->duid_len || - memcmp(&client->duid, optval, optlen) != 0) { - log_dhcp6_client(client, "%s DUID does not match", - dhcp6_message_type_to_string(message->type)); - - return -EINVAL; - } - clientid = true; - - break; - - case DHCP6_OPTION_SERVERID: - r = dhcp6_lease_get_serverid(lease, &id, &id_len); - if (r >= 0 && id) { - log_dhcp6_client(client, "%s contains multiple serverids", - dhcp6_message_type_to_string(message->type)); - return -EINVAL; - } - - r = dhcp6_lease_set_serverid(lease, optval, optlen); - if (r < 0) - return r; - - break; - - case DHCP6_OPTION_PREFERENCE: - if (optlen != 1) - return -EINVAL; - - r = dhcp6_lease_set_preference(lease, *optval); - if (r < 0) - return r; - - break; - - case DHCP6_OPTION_STATUS_CODE: - if (optlen < 2) - return -EINVAL; - - status = optval[0] << 8 | optval[1]; - if (status) { - log_dhcp6_client(client, "%s Status %s", - dhcp6_message_type_to_string(message->type), - dhcp6_message_status_to_string(status)); - return -EINVAL; - } - - break; - - case DHCP6_OPTION_IA_NA: - r = dhcp6_option_parse_ia(&optval, &optlen, optcode, - &lease->ia); - if (r < 0 && r != -ENOMSG) - return r; - - r = dhcp6_lease_get_iaid(lease, &iaid_lease); - if (r < 0) - return r; - - if (client->ia_na.id != iaid_lease) { - log_dhcp6_client(client, "%s has wrong IAID", - dhcp6_message_type_to_string(message->type)); - return -EINVAL; - } - - break; - - case DHCP6_OPTION_RAPID_COMMIT: - r = dhcp6_lease_set_rapid_commit(lease); - if (r < 0) - return r; - - break; - } - } - - if ((r < 0 && r != -ENOMSG) || !clientid) { - log_dhcp6_client(client, "%s has incomplete options", - dhcp6_message_type_to_string(message->type)); - return -EINVAL; - } - - r = dhcp6_lease_get_serverid(lease, &id, &id_len); - if (r < 0) - log_dhcp6_client(client, "%s has no server id", - dhcp6_message_type_to_string(message->type)); - - return r; -} - -static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, - size_t len) -{ - int r; - _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; - bool rapid_commit; - - if (reply->type != DHCP6_REPLY) - return 0; - - r = dhcp6_lease_new(&lease); - if (r < 0) - return -ENOMEM; - - r = client_parse_message(client, reply, len, lease); - if (r < 0) - return r; - - if (client->state == DHCP6_STATE_SOLICITATION) { - r = dhcp6_lease_get_rapid_commit(lease, &rapid_commit); - if (r < 0) - return r; - - if (!rapid_commit) - return 0; - } - - if (client->lease) - dhcp6_lease_clear_timers(&client->lease->ia); - - client->lease = sd_dhcp6_lease_unref(client->lease); - client->lease = lease; - lease = NULL; - - return DHCP6_STATE_BOUND; -} - -static int client_receive_advertise(sd_dhcp6_client *client, - DHCP6Message *advertise, size_t len) { - int r; - _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; - uint8_t pref_advertise = 0, pref_lease = 0; - - if (advertise->type != DHCP6_ADVERTISE) - return 0; - - r = dhcp6_lease_new(&lease); - if (r < 0) - return r; - - r = client_parse_message(client, advertise, len, lease); - if (r < 0) - return r; - - r = dhcp6_lease_get_preference(lease, &pref_advertise); - if (r < 0) - return r; - - r = dhcp6_lease_get_preference(client->lease, &pref_lease); - if (!client->lease || r < 0 || pref_advertise > pref_lease) { - if (client->lease) { - dhcp6_lease_clear_timers(&client->lease->ia); - sd_dhcp6_lease_unref(client->lease); - } - client->lease = lease; - lease = NULL; - r = 0; - } - - if (pref_advertise == 255 || client->retransmit_count > 1) - r = DHCP6_STATE_REQUEST; - - return r; -} - -static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, - void *userdata) { - sd_dhcp6_client *client = userdata; - DHCP6_CLIENT_DONT_DESTROY(client); - _cleanup_free_ DHCP6Message *message = NULL; - int r, buflen, len; - - assert(s); - assert(client); - assert(client->event); - - r = ioctl(fd, FIONREAD, &buflen); - if (r < 0 || buflen <= 0) - buflen = DHCP6_MIN_OPTIONS_SIZE; - - message = malloc0(buflen); - if (!message) - return -ENOMEM; - - len = read(fd, message, buflen); - if ((size_t)len < sizeof(DHCP6Message)) { - log_dhcp6_client(client, "could not receive message from UDP socket: %m"); - return 0; - } - - switch(message->type) { - case DHCP6_SOLICIT: - case DHCP6_REQUEST: - case DHCP6_CONFIRM: - case DHCP6_RENEW: - case DHCP6_REBIND: - case DHCP6_RELEASE: - case DHCP6_DECLINE: - case DHCP6_INFORMATION_REQUEST: - case DHCP6_RELAY_FORW: - case DHCP6_RELAY_REPL: - return 0; - - case DHCP6_ADVERTISE: - case DHCP6_REPLY: - case DHCP6_RECONFIGURE: - break; - - default: - log_dhcp6_client(client, "unknown message type %d", - message->type); - return 0; - } - - if (client->transaction_id != (message->transaction_id & - htobe32(0x00ffffff))) - return 0; - - switch (client->state) { - case DHCP6_STATE_SOLICITATION: - r = client_receive_advertise(client, message, len); - - if (r == DHCP6_STATE_REQUEST) { - client_start(client, r); - - break; - } - - /* fall through for Soliciation Rapid Commit option check */ - case DHCP6_STATE_REQUEST: - case DHCP6_STATE_RENEW: - case DHCP6_STATE_REBIND: - - r = client_receive_reply(client, message, len); - if (r < 0) - return 0; - - if (r == DHCP6_STATE_BOUND) { - - r = client_start(client, DHCP6_STATE_BOUND); - if (r < 0) { - client_stop(client, r); - return 0; - } - - client_notify(client, DHCP6_EVENT_IP_ACQUIRE); - } - - break; - - case DHCP6_STATE_BOUND: - - break; - - case DHCP6_STATE_STOPPED: - return 0; - } - - if (r >= 0) { - log_dhcp6_client(client, "Recv %s", - dhcp6_message_type_to_string(message->type)); - } - - return 0; -} - -static int client_start(sd_dhcp6_client *client, enum DHCP6State state) -{ - int r; - usec_t timeout, time_now; - char time_string[FORMAT_TIMESPAN_MAX]; - - assert_return(client, -EINVAL); - assert_return(client->event, -EINVAL); - assert_return(client->index > 0, -EINVAL); - assert_return(client->state != state, -EINVAL); - - client->timeout_resend_expire = - sd_event_source_unref(client->timeout_resend_expire); - client->timeout_resend = sd_event_source_unref(client->timeout_resend); - client->retransmit_time = 0; - client->retransmit_count = 0; - - if (client->state == DHCP6_STATE_STOPPED) { - time_now = now(clock_boottime_or_monotonic()); - } else { - r = sd_event_now(client->event, clock_boottime_or_monotonic(), - &time_now); - if (r < 0) - return r; - } - - switch (state) { - case DHCP6_STATE_STOPPED: - case DHCP6_STATE_SOLICITATION: - - r = client_ensure_iaid(client); - if (r < 0) - return r; - - r = dhcp6_network_bind_udp_socket(client->index, NULL); - if (r < 0) - return r; - - client->fd = r; - - r = sd_event_add_io(client->event, &client->receive_message, - client->fd, EPOLLIN, client_receive_message, - client); - if (r < 0) - return r; - - r = sd_event_source_set_priority(client->receive_message, - client->event_priority); - if (r < 0) - return r; - - r = sd_event_source_set_description(client->receive_message, "dhcp6-receive-message"); - if (r < 0) - return r; - - client->state = DHCP6_STATE_SOLICITATION; - - break; - - case DHCP6_STATE_REQUEST: - case DHCP6_STATE_RENEW: - case DHCP6_STATE_REBIND: - - client->state = state; - - break; - - case DHCP6_STATE_BOUND: - - if (client->lease->ia.lifetime_t1 == 0xffffffff || - client->lease->ia.lifetime_t2 == 0xffffffff) { - - log_dhcp6_client(client, "infinite T1 0x%08x or T2 0x%08x", - be32toh(client->lease->ia.lifetime_t1), - be32toh(client->lease->ia.lifetime_t2)); - - return 0; - } - - timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC); - - log_dhcp6_client(client, "T1 expires in %s", - format_timespan(time_string, - FORMAT_TIMESPAN_MAX, - timeout, 0)); - - r = sd_event_add_time(client->event, - &client->lease->ia.timeout_t1, - clock_boottime_or_monotonic(), time_now + timeout, - 10 * USEC_PER_SEC, client_timeout_t1, - client); - if (r < 0) - return r; - - r = sd_event_source_set_priority(client->lease->ia.timeout_t1, - client->event_priority); - if (r < 0) - return r; - - r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout"); - if (r < 0) - return r; - - timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC); - - log_dhcp6_client(client, "T2 expires in %s", - format_timespan(time_string, - FORMAT_TIMESPAN_MAX, - timeout, 0)); - - r = sd_event_add_time(client->event, - &client->lease->ia.timeout_t2, - clock_boottime_or_monotonic(), time_now + timeout, - 10 * USEC_PER_SEC, client_timeout_t2, - client); - if (r < 0) - return r; - - r = sd_event_source_set_priority(client->lease->ia.timeout_t2, - client->event_priority); - if (r < 0) - return r; - - r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout"); - if (r < 0) - return r; - - client->state = state; - - return 0; - } - - client->transaction_id = random_u32() & htobe32(0x00ffffff); - client->transaction_start = time_now; - - r = sd_event_add_time(client->event, &client->timeout_resend, - clock_boottime_or_monotonic(), 0, 0, client_timeout_resend, - client); - if (r < 0) - return r; - - r = sd_event_source_set_priority(client->timeout_resend, - client->event_priority); - if (r < 0) - return r; - - r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timeout"); - if (r < 0) - return r; - - return 0; -} - -int sd_dhcp6_client_stop(sd_dhcp6_client *client) -{ - client_stop(client, DHCP6_EVENT_STOP); - - return 0; -} - -int sd_dhcp6_client_start(sd_dhcp6_client *client) -{ - int r = 0; - - assert_return(client, -EINVAL); - assert_return(client->event, -EINVAL); - assert_return(client->index > 0, -EINVAL); - - r = client_reset(client); - if (r < 0) - return r; - - return client_start(client, DHCP6_STATE_SOLICITATION); -} - -int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, - int priority) -{ - int r; - - assert_return(client, -EINVAL); - assert_return(!client->event, -EBUSY); - - if (event) - client->event = sd_event_ref(event); - else { - r = sd_event_default(&client->event); - if (r < 0) - return 0; - } - - client->event_priority = priority; - - return 0; -} - -int sd_dhcp6_client_detach_event(sd_dhcp6_client *client) { - assert_return(client, -EINVAL); - - client->event = sd_event_unref(client->event); - - return 0; -} - -sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) { - if (!client) - return NULL; - - return client->event; -} - -sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) { - if (client) - assert_se(REFCNT_INC(client->n_ref) >= 2); - - return client; -} - -sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) { - if (client && REFCNT_DEC(client->n_ref) <= 0) { - client_reset(client); - - sd_dhcp6_client_detach_event(client); - - free(client->req_opts); - free(client); - - return NULL; - } - - return client; -} - -int sd_dhcp6_client_new(sd_dhcp6_client **ret) -{ - _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL; -#if 0 /* NM_IGNORED */ - sd_id128_t machine_id; - int r; -#endif - size_t t; - - assert_return(ret, -EINVAL); - - client = new0(sd_dhcp6_client, 1); - if (!client) - return -ENOMEM; - - client->n_ref = REFCNT_INIT; - - client->ia_na.type = DHCP6_OPTION_IA_NA; - - client->index = -1; - - client->fd = -1; - -#if 0 /* NM_IGNORED */ - /* initialize DUID */ - client->duid.en.type = htobe16(DHCP6_DUID_EN); - client->duid.en.pen = htobe32(SYSTEMD_PEN); - client->duid_len = sizeof(client->duid.en); - - r = sd_id128_get_machine(&machine_id); - if (r < 0) - return r; - - /* a bit of snake-oil perhaps, but no need to expose the machine-id - directly */ - siphash24(client->duid.en.id, &machine_id, sizeof(machine_id), HASH_KEY.bytes); -#endif - - client->req_opts_len = ELEMENTSOF(default_req_opts); - - client->req_opts = new0(be16_t, client->req_opts_len); - if (!client->req_opts) - return -ENOMEM; - - for (t = 0; t < client->req_opts_len; t++) - client->req_opts[t] = htobe16(default_req_opts[t]); - - *ret = client; - client = NULL; - - return 0; -} - -/*******************************************/ -/* NetworkManager additions */ - -int sd_dhcp6_client_set_ifname(sd_dhcp6_client *client, const char *ifname) -{ - assert_return(client, -EINVAL); - assert_return(ifname, -EINVAL); - assert_return(strlen (ifname) < sizeof (client->ifname), -EINVAL); - - strcpy(client->ifname, ifname); - return 0; -} - diff --git a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c b/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c deleted file mode 100644 index 0df6984d..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/libsystemd-network/sd-dhcp6-lease.c +++ /dev/null @@ -1,223 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "config.h" - -#include "nm-sd-adapt.h" - -#include - -#include "util.h" - -#include "dhcp6-lease-internal.h" - -int dhcp6_lease_clear_timers(DHCP6IA *ia) { - assert_return(ia, -EINVAL); - - ia->timeout_t1 = sd_event_source_unref(ia->timeout_t1); - ia->timeout_t2 = sd_event_source_unref(ia->timeout_t2); - - return 0; -} - -int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) { - DHCP6Address *addr; - uint32_t valid = 0, t; - - assert_return(ia, -EINVAL); - assert_return(expire, -EINVAL); - - LIST_FOREACH(addresses, addr, ia->addresses) { - t = be32toh(addr->iaaddr.lifetime_valid); - if (valid < t) - valid = t; - } - - t = be32toh(ia->lifetime_t2); - if (t > valid) - return -EINVAL; - - *expire = valid - t; - - return 0; -} - -DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) { - DHCP6Address *address; - - if (!ia) - return NULL; - - dhcp6_lease_clear_timers(ia); - - while (ia->addresses) { - address = ia->addresses; - - LIST_REMOVE(addresses, ia->addresses, address); - - free(address); - } - - return NULL; -} - -int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id, - size_t len) { - assert_return(lease, -EINVAL); - assert_return(id, -EINVAL); - - free(lease->serverid); - - lease->serverid = memdup(id, len); - if (!lease->serverid) - return -EINVAL; - - lease->serverid_len = len; - - return 0; -} - -int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len) { - assert_return(lease, -EINVAL); - assert_return(id, -EINVAL); - assert_return(len, -EINVAL); - - *id = lease->serverid; - *len = lease->serverid_len; - - return 0; -} - -int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference) { - assert_return(lease, -EINVAL); - - lease->preference = preference; - - return 0; -} - -int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference) { - assert_return(lease, -EINVAL); - assert_return(preference, -EINVAL); - - *preference = lease->preference; - - return 0; -} - -int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease) { - assert_return(lease, -EINVAL); - - lease->rapid_commit = true; - - return 0; -} - -int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit) { - assert_return(lease, -EINVAL); - assert_return(rapid_commit, -EINVAL); - - *rapid_commit = lease->rapid_commit; - - return 0; -} - -int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) { - assert_return(lease, -EINVAL); - assert_return(iaid, -EINVAL); - - *iaid = lease->ia.id; - - return 0; -} - -int sd_dhcp6_lease_get_next_address(sd_dhcp6_lease *lease, - struct in6_addr *addr, - uint32_t *lifetime_preferred, - uint32_t *lifetime_valid) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(lifetime_preferred, -EINVAL); - assert_return(lifetime_valid, -EINVAL); - - if (!lease->addr_iter) - return -ENOMSG; - - memcpy(addr, &lease->addr_iter->iaaddr.address, - sizeof(struct in6_addr)); - *lifetime_preferred = - be32toh(lease->addr_iter->iaaddr.lifetime_preferred); - *lifetime_valid = be32toh(lease->addr_iter->iaaddr.lifetime_valid); - - lease->addr_iter = lease->addr_iter->addresses_next; - - return 0; -} - -int sd_dhcp6_lease_get_first_address(sd_dhcp6_lease *lease, - struct in6_addr *addr, - uint32_t *lifetime_preferred, - uint32_t *lifetime_valid) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(lifetime_preferred, -EINVAL); - assert_return(lifetime_valid, -EINVAL); - - if (!lease->ia.addresses) - return -ENOMSG; - - lease->addr_iter = lease->ia.addresses; - - return sd_dhcp6_lease_get_next_address(lease, addr, lifetime_preferred, - lifetime_valid); -} - -sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease) { - if (lease) - assert_se(REFCNT_INC(lease->n_ref) >= 2); - - return lease; -} - -sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) { - if (lease && REFCNT_DEC(lease->n_ref) <= 0) { - free(lease->serverid); - dhcp6_lease_free_ia(&lease->ia); - - free(lease); - } - - return NULL; -} - -int dhcp6_lease_new(sd_dhcp6_lease **ret) { - sd_dhcp6_lease *lease; - - lease = new0(sd_dhcp6_lease, 1); - if (!lease) - return -ENOMEM; - - lease->n_ref = REFCNT_INIT; - - LIST_HEAD_INIT(lease->ia.addresses); - - *ret = lease; - return 0; -} diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/async.h b/src/dhcp-manager/systemd-dhcp/src/shared/async.h deleted file mode 100644 index 7f1ef795..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/async.h +++ /dev/null @@ -1,27 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -int asynchronous_job(void* (*func)(void *p), void *arg); - -int asynchronous_sync(void); -int asynchronous_close(int fd); diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/fileio.c b/src/dhcp-manager/systemd-dhcp/src/shared/fileio.c deleted file mode 100644 index 0757d5d9..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/fileio.c +++ /dev/null @@ -1,817 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "config.h" - -#include - -#include "util.h" -#include "strv.h" -#include "utf8.h" -#include "ctype.h" -#include "fileio.h" - -int write_string_stream(FILE *f, const char *line) { - assert(f); - assert(line); - - errno = 0; - - fputs(line, f); - if (!endswith(line, "\n")) - fputc('\n', f); - - fflush(f); - - if (ferror(f)) - return errno ? -errno : -EIO; - - return 0; -} - -int write_string_file(const char *fn, const char *line) { - _cleanup_fclose_ FILE *f = NULL; - - assert(fn); - assert(line); - - f = fopen(fn, "we"); - if (!f) - return -errno; - - return write_string_stream(f, line); -} - -int write_string_file_no_create(const char *fn, const char *line) { - _cleanup_fclose_ FILE *f = NULL; - int fd; - - assert(fn); - assert(line); - - /* We manually build our own version of fopen(..., "we") that - * works without O_CREAT */ - fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return -errno; - - f = fdopen(fd, "we"); - if (!f) { - safe_close(fd); - return -errno; - } - - return write_string_stream(f, line); -} - -int write_string_file_atomic(const char *fn, const char *line) { - _cleanup_fclose_ FILE *f = NULL; - _cleanup_free_ char *p = NULL; - int r; - - assert(fn); - assert(line); - - r = fopen_temporary(fn, &f, &p); - if (r < 0) - return r; - - fchmod_umask(fileno(f), 0644); - - r = write_string_stream(f, line); - if (r >= 0) { - if (rename(p, fn) < 0) - r = -errno; - } - - if (r < 0) - unlink(p); - - return r; -} - -int read_one_line_file(const char *fn, char **line) { - _cleanup_fclose_ FILE *f = NULL; - char t[LINE_MAX], *c; - - assert(fn); - assert(line); - - f = fopen(fn, "re"); - if (!f) - return -errno; - - if (!fgets(t, sizeof(t), f)) { - - if (ferror(f)) - return errno ? -errno : -EIO; - - t[0] = 0; - } - - c = strdup(t); - if (!c) - return -ENOMEM; - truncate_nl(c); - - *line = c; - return 0; -} - -int read_full_stream(FILE *f, char **contents, size_t *size) { - size_t n, l; - _cleanup_free_ char *buf = NULL; - struct stat st; - - assert(f); - assert(contents); - - if (fstat(fileno(f), &st) < 0) - return -errno; - - n = LINE_MAX; - - if (S_ISREG(st.st_mode)) { - - /* Safety check */ - if (st.st_size > 4*1024*1024) - return -E2BIG; - - /* Start with the right file size, but be prepared for - * files from /proc which generally report a file size - * of 0 */ - if (st.st_size > 0) - n = st.st_size; - } - - l = 0; - for (;;) { - char *t; - size_t k; - - t = realloc(buf, n+1); - if (!t) - return -ENOMEM; - - buf = t; - k = fread(buf + l, 1, n - l, f); - - if (k <= 0) { - if (ferror(f)) - return -errno; - - break; - } - - l += k; - n *= 2; - - /* Safety check */ - if (n > 4*1024*1024) - return -E2BIG; - } - - buf[l] = 0; - *contents = buf; - buf = NULL; /* do not free */ - - if (size) - *size = l; - - return 0; -} - -int read_full_file(const char *fn, char **contents, size_t *size) { - _cleanup_fclose_ FILE *f = NULL; - - assert(fn); - assert(contents); - - f = fopen(fn, "re"); - if (!f) - return -errno; - - return read_full_stream(f, contents, size); -} - -static int parse_env_file_internal( - FILE *f, - const char *fname, - const char *newline, - int (*push) (const char *filename, unsigned line, - const char *key, char *value, void *userdata, int *n_pushed), - void *userdata, - int *n_pushed) { - - _cleanup_free_ char *contents = NULL, *key = NULL; - size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1; - char *p, *value = NULL; - int r; - unsigned line = 1; - - enum { - PRE_KEY, - KEY, - PRE_VALUE, - VALUE, - VALUE_ESCAPE, - SINGLE_QUOTE_VALUE, - SINGLE_QUOTE_VALUE_ESCAPE, - DOUBLE_QUOTE_VALUE, - DOUBLE_QUOTE_VALUE_ESCAPE, - COMMENT, - COMMENT_ESCAPE - } state = PRE_KEY; - - assert(newline); - - if (f) - r = read_full_stream(f, &contents, NULL); - else - r = read_full_file(fname, &contents, NULL); - if (r < 0) - return r; - - for (p = contents; *p; p++) { - char c = *p; - - switch (state) { - - case PRE_KEY: - if (strchr(COMMENTS, c)) - state = COMMENT; - else if (!strchr(WHITESPACE, c)) { - state = KEY; - last_key_whitespace = (size_t) -1; - - if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { - r = -ENOMEM; - goto fail; - } - - key[n_key++] = c; - } - break; - - case KEY: - if (strchr(newline, c)) { - state = PRE_KEY; - line ++; - n_key = 0; - } else if (c == '=') { - state = PRE_VALUE; - last_value_whitespace = (size_t) -1; - } else { - if (!strchr(WHITESPACE, c)) - last_key_whitespace = (size_t) -1; - else if (last_key_whitespace == (size_t) -1) - last_key_whitespace = n_key; - - if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { - r = -ENOMEM; - goto fail; - } - - key[n_key++] = c; - } - - break; - - case PRE_VALUE: - if (strchr(newline, c)) { - state = PRE_KEY; - line ++; - key[n_key] = 0; - - if (value) - value[n_value] = 0; - - /* strip trailing whitespace from key */ - if (last_key_whitespace != (size_t) -1) - key[last_key_whitespace] = 0; - - r = push(fname, line, key, value, userdata, n_pushed); - if (r < 0) - goto fail; - - n_key = 0; - value = NULL; - value_alloc = n_value = 0; - - } else if (c == '\'') - state = SINGLE_QUOTE_VALUE; - else if (c == '\"') - state = DOUBLE_QUOTE_VALUE; - else if (c == '\\') - state = VALUE_ESCAPE; - else if (!strchr(WHITESPACE, c)) { - state = VALUE; - - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } - - value[n_value++] = c; - } - - break; - - case VALUE: - if (strchr(newline, c)) { - state = PRE_KEY; - line ++; - - key[n_key] = 0; - - if (value) - value[n_value] = 0; - - /* Chomp off trailing whitespace from value */ - if (last_value_whitespace != (size_t) -1) - value[last_value_whitespace] = 0; - - /* strip trailing whitespace from key */ - if (last_key_whitespace != (size_t) -1) - key[last_key_whitespace] = 0; - - r = push(fname, line, key, value, userdata, n_pushed); - if (r < 0) - goto fail; - - n_key = 0; - value = NULL; - value_alloc = n_value = 0; - - } else if (c == '\\') { - state = VALUE_ESCAPE; - last_value_whitespace = (size_t) -1; - } else { - if (!strchr(WHITESPACE, c)) - last_value_whitespace = (size_t) -1; - else if (last_value_whitespace == (size_t) -1) - last_value_whitespace = n_value; - - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } - - value[n_value++] = c; - } - - break; - - case VALUE_ESCAPE: - state = VALUE; - - if (!strchr(newline, c)) { - /* Escaped newlines we eat up entirely */ - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } - - value[n_value++] = c; - } - break; - - case SINGLE_QUOTE_VALUE: - if (c == '\'') - state = PRE_VALUE; - else if (c == '\\') - state = SINGLE_QUOTE_VALUE_ESCAPE; - else { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } - - value[n_value++] = c; - } - - break; - - case SINGLE_QUOTE_VALUE_ESCAPE: - state = SINGLE_QUOTE_VALUE; - - if (!strchr(newline, c)) { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } - - value[n_value++] = c; - } - break; - - case DOUBLE_QUOTE_VALUE: - if (c == '\"') - state = PRE_VALUE; - else if (c == '\\') - state = DOUBLE_QUOTE_VALUE_ESCAPE; - else { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } - - value[n_value++] = c; - } - - break; - - case DOUBLE_QUOTE_VALUE_ESCAPE: - state = DOUBLE_QUOTE_VALUE; - - if (!strchr(newline, c)) { - if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { - r = -ENOMEM; - goto fail; - } - - value[n_value++] = c; - } - break; - - case COMMENT: - if (c == '\\') - state = COMMENT_ESCAPE; - else if (strchr(newline, c)) { - state = PRE_KEY; - line ++; - } - break; - - case COMMENT_ESCAPE: - state = COMMENT; - break; - } - } - - if (state == PRE_VALUE || - state == VALUE || - state == VALUE_ESCAPE || - state == SINGLE_QUOTE_VALUE || - state == SINGLE_QUOTE_VALUE_ESCAPE || - state == DOUBLE_QUOTE_VALUE || - state == DOUBLE_QUOTE_VALUE_ESCAPE) { - - key[n_key] = 0; - - if (value) - value[n_value] = 0; - - if (state == VALUE) - if (last_value_whitespace != (size_t) -1) - value[last_value_whitespace] = 0; - - /* strip trailing whitespace from key */ - if (last_key_whitespace != (size_t) -1) - key[last_key_whitespace] = 0; - - r = push(fname, line, key, value, userdata, n_pushed); - if (r < 0) - goto fail; - } - - return 0; - -fail: - free(value); - return r; -} - -static int parse_env_file_push( - const char *filename, unsigned line, - const char *key, char *value, - void *userdata, - int *n_pushed) { - - const char *k; - va_list aq, *ap = userdata; - - if (!utf8_is_valid(key)) { - _cleanup_free_ char *p = utf8_escape_invalid(key); - - log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p); - return -EINVAL; - } - - if (value && !utf8_is_valid(value)) { - _cleanup_free_ char *p = utf8_escape_invalid(value); - - log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p); - return -EINVAL; - } - - va_copy(aq, *ap); - - while ((k = va_arg(aq, const char *))) { - char **v; - - v = va_arg(aq, char **); - - if (streq(key, k)) { - va_end(aq); - free(*v); - *v = value; - - if (n_pushed) - (*n_pushed)++; - - return 1; - } - } - - va_end(aq); - free(value); - - return 0; -} - -int parse_env_file( - const char *fname, - const char *newline, ...) { - - va_list ap; - int r, n_pushed = 0; - - if (!newline) - newline = NEWLINE; - - va_start(ap, newline); - r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed); - va_end(ap); - - return r < 0 ? r : n_pushed; -} - -static int load_env_file_push( - const char *filename, unsigned line, - const char *key, char *value, - void *userdata, - int *n_pushed) { - char ***m = userdata; - char *p; - int r; - - if (!utf8_is_valid(key)) { - _cleanup_free_ char *t = utf8_escape_invalid(key); - - log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t); - return -EINVAL; - } - - if (value && !utf8_is_valid(value)) { - _cleanup_free_ char *t = utf8_escape_invalid(value); - - log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t); - return -EINVAL; - } - - p = strjoin(key, "=", strempty(value), NULL); - if (!p) - return -ENOMEM; - - r = strv_consume(m, p); - if (r < 0) - return r; - - if (n_pushed) - (*n_pushed)++; - - free(value); - return 0; -} - -int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) { - char **m = NULL; - int r; - - if (!newline) - newline = NEWLINE; - - r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL); - if (r < 0) { - strv_free(m); - return r; - } - - *rl = m; - return 0; -} - -static int load_env_file_push_pairs( - const char *filename, unsigned line, - const char *key, char *value, - void *userdata, - int *n_pushed) { - char ***m = userdata; - int r; - - if (!utf8_is_valid(key)) { - _cleanup_free_ char *t = utf8_escape_invalid(key); - - log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t); - return -EINVAL; - } - - if (value && !utf8_is_valid(value)) { - _cleanup_free_ char *t = utf8_escape_invalid(value); - - log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t); - return -EINVAL; - } - - r = strv_extend(m, key); - if (r < 0) - return -ENOMEM; - - if (!value) { - r = strv_extend(m, ""); - if (r < 0) - return -ENOMEM; - } else { - r = strv_push(m, value); - if (r < 0) - return r; - } - - if (n_pushed) - (*n_pushed)++; - - return 0; -} - -int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) { - char **m = NULL; - int r; - - if (!newline) - newline = NEWLINE; - - r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL); - if (r < 0) { - strv_free(m); - return r; - } - - *rl = m; - return 0; -} - -static void write_env_var(FILE *f, const char *v) { - const char *p; - - p = strchr(v, '='); - if (!p) { - /* Fallback */ - fputs(v, f); - fputc('\n', f); - return; - } - - p++; - fwrite(v, 1, p-v, f); - - if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) { - fputc('\"', f); - - for (; *p; p++) { - if (strchr(SHELL_NEED_ESCAPE, *p)) - fputc('\\', f); - - fputc(*p, f); - } - - fputc('\"', f); - } else - fputs(p, f); - - fputc('\n', f); -} - -int write_env_file(const char *fname, char **l) { - _cleanup_fclose_ FILE *f = NULL; - _cleanup_free_ char *p = NULL; - char **i; - int r; - - assert(fname); - - r = fopen_temporary(fname, &f, &p); - if (r < 0) - return r; - - fchmod_umask(fileno(f), 0644); - - STRV_FOREACH(i, l) - write_env_var(f, *i); - - r = fflush_and_check(f); - if (r >= 0) { - if (rename(p, fname) >= 0) - return 0; - - r = -errno; - } - - unlink(p); - return r; -} - -int executable_is_script(const char *path, char **interpreter) { - int r; - _cleanup_free_ char *line = NULL; - int len; - char *ans; - - assert(path); - - r = read_one_line_file(path, &line); - if (r < 0) - return r; - - if (!startswith(line, "#!")) - return 0; - - ans = strstrip(line + 2); - len = strcspn(ans, " \t"); - - if (len == 0) - return 0; - - ans = strndup(ans, len); - if (!ans) - return -ENOMEM; - - *interpreter = ans; - return 1; -} - -/** - * Retrieve one field from a file like /proc/self/status. pattern - * should start with '\n' and end with a ':'. Whitespace and zeros - * after the ':' will be skipped. field must be freed afterwards. - */ -int get_status_field(const char *filename, const char *pattern, char **field) { - _cleanup_free_ char *status = NULL; - char *t; - size_t len; - int r; - - assert(filename); - assert(pattern); - assert(field); - - r = read_full_file(filename, &status, NULL); - if (r < 0) - return r; - - t = strstr(status, pattern); - if (!t) - return -ENOENT; - - t += strlen(pattern); - if (*t) { - t += strspn(t, " \t"); - - /* Also skip zeros, because when this is used for - * capabilities, we don't want the zeros. This way the - * same capability set always maps to the same string, - * irrespective of the total capability set size. For - * other numbers it shouldn't matter. */ - t += strspn(t, "0"); - /* Back off one char if there's nothing but whitespace - and zeros */ - if (!*t || isspace(*t)) - t --; - } - - len = strcspn(t, WHITESPACE); - - *field = strndup(t, len); - if (!*field) - return -ENOMEM; - - return 0; -} diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/fileio.h b/src/dhcp-manager/systemd-dhcp/src/shared/fileio.h deleted file mode 100644 index 5ae51c1e..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/fileio.h +++ /dev/null @@ -1,45 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ -#include -#include - -#include "macro.h" - -int write_string_stream(FILE *f, const char *line); -int write_string_file(const char *fn, const char *line); -int write_string_file_no_create(const char *fn, const char *line); -int write_string_file_atomic(const char *fn, const char *line); - -int read_one_line_file(const char *fn, char **line); -int read_full_file(const char *fn, char **contents, size_t *size); -int read_full_stream(FILE *f, char **contents, size_t *size); - -int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; -int load_env_file(FILE *f, const char *fname, const char *separator, char ***l); -int load_env_file_pairs(FILE *f, const char *fname, const char *separator, char ***l); - -int write_env_file(const char *fname, char **l); - -int executable_is_script(const char *path, char **interpreter); - -int get_status_field(const char *filename, const char *pattern, char **field); diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c b/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c deleted file mode 100644 index 27edeb8d..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.c +++ /dev/null @@ -1,294 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "config.h" - -#include - -#include "in-addr-util.h" - -int in_addr_is_null(int family, const union in_addr_union *u) { - assert(u); - - if (family == AF_INET) - return u->in.s_addr == 0; - - if (family == AF_INET6) - return - u->in6.s6_addr32[0] == 0 && - u->in6.s6_addr32[1] == 0 && - u->in6.s6_addr32[2] == 0 && - u->in6.s6_addr32[3] == 0; - - return -EAFNOSUPPORT; -} - -int in_addr_is_link_local(int family, const union in_addr_union *u) { - assert(u); - - if (family == AF_INET) - return (be32toh(u->in.s_addr) & 0xFFFF0000) == (169U << 24 | 254U << 16); - - if (family == AF_INET6) - return IN6_IS_ADDR_LINKLOCAL(&u->in6); - - return -EAFNOSUPPORT; -} - -int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) { - assert(a); - assert(b); - - if (family == AF_INET) - return a->in.s_addr == b->in.s_addr; - - if (family == AF_INET6) - return - a->in6.s6_addr32[0] == b->in6.s6_addr32[0] && - a->in6.s6_addr32[1] == b->in6.s6_addr32[1] && - a->in6.s6_addr32[2] == b->in6.s6_addr32[2] && - a->in6.s6_addr32[3] == b->in6.s6_addr32[3]; - - return -EAFNOSUPPORT; -} - -int in_addr_prefix_intersect( - int family, - const union in_addr_union *a, - unsigned aprefixlen, - const union in_addr_union *b, - unsigned bprefixlen) { - - unsigned m; - - assert(a); - assert(b); - - /* Checks whether there are any addresses that are in both - * networks */ - - m = MIN(aprefixlen, bprefixlen); - - if (family == AF_INET) { - uint32_t x, nm; - - x = be32toh(a->in.s_addr ^ b->in.s_addr); - nm = (m == 0) ? 0 : 0xFFFFFFFFUL << (32 - m); - - return (x & nm) == 0; - } - - if (family == AF_INET6) { - unsigned i; - - if (m > 128) - m = 128; - - for (i = 0; i < 16; i++) { - uint8_t x, nm; - - x = a->in6.s6_addr[i] ^ b->in6.s6_addr[i]; - - if (m < 8) - nm = 0xFF << (8 - m); - else - nm = 0xFF; - - if ((x & nm) != 0) - return 0; - - if (m > 8) - m -= 8; - else - m = 0; - } - - return 1; - } - - return -EAFNOSUPPORT; -} - -int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) { - assert(u); - - /* Increases the network part of an address by one. Returns - * positive it that succeeds, or 0 if this overflows. */ - - if (prefixlen <= 0) - return 0; - - if (family == AF_INET) { - uint32_t c, n; - - if (prefixlen > 32) - prefixlen = 32; - - c = be32toh(u->in.s_addr); - n = c + (1UL << (32 - prefixlen)); - if (n < c) - return 0; - n &= 0xFFFFFFFFUL << (32 - prefixlen); - - u->in.s_addr = htobe32(n); - return 1; - } - - if (family == AF_INET6) { - struct in6_addr add = {}, result; - uint8_t overflow = 0; - unsigned i; - - if (prefixlen > 128) - prefixlen = 128; - - /* First calculate what we have to add */ - add.s6_addr[(prefixlen-1) / 8] = 1 << (7 - (prefixlen-1) % 8); - - for (i = 16; i > 0; i--) { - unsigned j = i - 1; - - result.s6_addr[j] = u->in6.s6_addr[j] + add.s6_addr[j] + overflow; - overflow = (result.s6_addr[j] < u->in6.s6_addr[j]); - } - - if (overflow) - return 0; - - u->in6 = result; - return 1; - } - - return -EAFNOSUPPORT; -} - -int in_addr_to_string(int family, const union in_addr_union *u, char **ret) { - char *x; - size_t l; - - assert(u); - assert(ret); - - if (family == AF_INET) - l = INET_ADDRSTRLEN; - else if (family == AF_INET6) - l = INET6_ADDRSTRLEN; - else - return -EAFNOSUPPORT; - - x = new(char, l); - if (!x) - return -ENOMEM; - - errno = 0; - if (!inet_ntop(family, u, x, l)) { - free(x); - return errno ? -errno : -EINVAL; - } - - *ret = x; - return 0; -} - -int in_addr_from_string(int family, const char *s, union in_addr_union *ret) { - - assert(s); - assert(ret); - - if (!IN_SET(family, AF_INET, AF_INET6)) - return -EAFNOSUPPORT; - - errno = 0; - if (inet_pton(family, s, ret) <= 0) - return errno ? -errno : -EINVAL; - - return 0; -} - -int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret) { - int r; - - assert(s); - assert(family); - assert(ret); - - r = in_addr_from_string(AF_INET, s, ret); - if (r >= 0) { - *family = AF_INET; - return 0; - } - - r = in_addr_from_string(AF_INET6, s, ret); - if (r >= 0) { - *family = AF_INET6; - return 0; - } - - return -EINVAL; -} - -unsigned in_addr_netmask_to_prefixlen(const struct in_addr *addr) { - assert(addr); - - return 32 - u32ctz(be32toh(addr->s_addr)); -} - -int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) { - uint8_t msb_octet = *(uint8_t*) addr; - - /* addr may not be aligned, so make sure we only access it byte-wise */ - - assert(addr); - assert(prefixlen); - - if (msb_octet < 128) - /* class A, leading bits: 0 */ - *prefixlen = 8; - else if (msb_octet < 192) - /* class B, leading bits 10 */ - *prefixlen = 16; - else if (msb_octet < 224) - /* class C, leading bits 110 */ - *prefixlen = 24; - else - /* class D or E, no default prefixlen */ - return -ERANGE; - - return 0; -} - -int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) { - unsigned char prefixlen; - int r; - - assert(addr); - assert(mask); - - r = in_addr_default_prefixlen(addr, &prefixlen); - if (r < 0) - return r; - - assert(prefixlen > 0 && prefixlen < 32); - - mask->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff); - - return 0; -} diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h b/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h deleted file mode 100644 index 8da030ce..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/in-addr-util.h +++ /dev/null @@ -1,49 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2014 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include - -#include "macro.h" -#include "util.h" - -union in_addr_union { - struct in_addr in; - struct in6_addr in6; -}; - -int in_addr_is_null(int family, const union in_addr_union *u); -int in_addr_is_link_local(int family, const union in_addr_union *u); -int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b); -int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen); -int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen); -int in_addr_to_string(int family, const union in_addr_union *u, char **ret); -int in_addr_from_string(int family, const char *s, union in_addr_union *ret); -int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret); -unsigned in_addr_netmask_to_prefixlen(const struct in_addr *addr); -int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen); -int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask); - -static inline size_t FAMILY_ADDRESS_SIZE(int family) { - assert(family == AF_INET || family == AF_INET6); - return family == AF_INET6 ? 16 : 4; -} diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/list.h b/src/dhcp-manager/systemd-dhcp/src/shared/list.h deleted file mode 100644 index c020f7e9..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/list.h +++ /dev/null @@ -1,138 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -/* The head of the linked list. Use this in the structure that shall - * contain the head of the linked list */ -#define LIST_HEAD(t,name) \ - t *name - -/* The pointers in the linked list's items. Use this in the item structure */ -#define LIST_FIELDS(t,name) \ - t *name##_next, *name##_prev - -/* Initialize the list's head */ -#define LIST_HEAD_INIT(head) \ - do { \ - (head) = NULL; } \ - while(false) - -/* Initialize a list item */ -#define LIST_INIT(name,item) \ - do { \ - typeof(*(item)) *_item = (item); \ - assert(_item); \ - _item->name##_prev = _item->name##_next = NULL; \ - } while(false) - -/* Prepend an item to the list */ -#define LIST_PREPEND(name,head,item) \ - do { \ - typeof(*(head)) **_head = &(head), *_item = (item); \ - assert(_item); \ - if ((_item->name##_next = *_head)) \ - _item->name##_next->name##_prev = _item; \ - _item->name##_prev = NULL; \ - *_head = _item; \ - } while(false) - -/* Remove an item from the list */ -#define LIST_REMOVE(name,head,item) \ - do { \ - typeof(*(head)) **_head = &(head), *_item = (item); \ - assert(_item); \ - if (_item->name##_next) \ - _item->name##_next->name##_prev = _item->name##_prev; \ - if (_item->name##_prev) \ - _item->name##_prev->name##_next = _item->name##_next; \ - else { \ - assert(*_head == _item); \ - *_head = _item->name##_next; \ - } \ - _item->name##_next = _item->name##_prev = NULL; \ - } while(false) - -/* Find the head of the list */ -#define LIST_FIND_HEAD(name,item,head) \ - do { \ - typeof(*(item)) *_item = (item); \ - if (!_item) \ - (head) = NULL; \ - else { \ - while (_item->name##_prev) \ - _item = _item->name##_prev; \ - (head) = _item; \ - } \ - } while (false) - -/* Find the tail of the list */ -#define LIST_FIND_TAIL(name,item,tail) \ - do { \ - typeof(*(item)) *_item = (item); \ - if (!_item) \ - (tail) = NULL; \ - else { \ - while (_item->name##_next) \ - _item = _item->name##_next; \ - (tail) = _item; \ - } \ - } while (false) - -/* Insert an item after another one (a = where, b = what) */ -#define LIST_INSERT_AFTER(name,head,a,b) \ - do { \ - typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \ - assert(_b); \ - if (!_a) { \ - if ((_b->name##_next = *_head)) \ - _b->name##_next->name##_prev = _b; \ - _b->name##_prev = NULL; \ - *_head = _b; \ - } else { \ - if ((_b->name##_next = _a->name##_next)) \ - _b->name##_next->name##_prev = _b; \ - _b->name##_prev = _a; \ - _a->name##_next = _b; \ - } \ - } while(false) - -#define LIST_JUST_US(name,item) \ - (!(item)->name##_prev && !(item)->name##_next) \ - -#define LIST_FOREACH(name,i,head) \ - for ((i) = (head); (i); (i) = (i)->name##_next) - -#define LIST_FOREACH_SAFE(name,i,n,head) \ - for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n)) - -#define LIST_FOREACH_BEFORE(name,i,p) \ - for ((i) = (p)->name##_prev; (i); (i) = (i)->name##_prev) - -#define LIST_FOREACH_AFTER(name,i,p) \ - for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next) - -/* Loop starting from p->next until p->prev. - p can be adjusted meanwhile. */ -#define LIST_LOOP_BUT_ONE(name,i,head,p) \ - for ((i) = (p)->name##_next ? (p)->name##_next : (head); \ - (i) != (p); \ - (i) = (i)->name##_next ? (i)->name##_next : (head)) diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/macro.h b/src/dhcp-manager/systemd-dhcp/src/shared/macro.h deleted file mode 100644 index bdda4dce..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/macro.h +++ /dev/null @@ -1,422 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#define _printf_(a,b) __attribute__ ((format (printf, a, b))) -#define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) -#define _sentinel_ __attribute__ ((sentinel)) -#define _unused_ __attribute__ ((unused)) -#define _destructor_ __attribute__ ((destructor)) -#define _pure_ __attribute__ ((pure)) -#define _const_ __attribute__ ((const)) -#define _deprecated_ __attribute__ ((deprecated)) -#define _packed_ __attribute__ ((packed)) -#define _malloc_ __attribute__ ((malloc)) -#define _weak_ __attribute__ ((weak)) -#define _likely_(x) (__builtin_expect(!!(x),1)) -#define _unlikely_(x) (__builtin_expect(!!(x),0)) -#define _public_ __attribute__ ((visibility("default"))) -#define _hidden_ __attribute__ ((visibility("hidden"))) -#define _weakref_(x) __attribute__((weakref(#x))) -#define _alignas_(x) __attribute__((aligned(__alignof(x)))) -#define _cleanup_(x) __attribute__((cleanup(x))) - -#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) || defined (__clang__) -/* Temporarily disable some warnings */ -#define DISABLE_WARNING_DECLARATION_AFTER_STATEMENT \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wdeclaration-after-statement\"") - -#define DISABLE_WARNING_FORMAT_NONLITERAL \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") - -#define DISABLE_WARNING_MISSING_PROTOTYPES \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wmissing-prototypes\"") - -#define DISABLE_WARNING_NONNULL \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wnonnull\"") - -#define DISABLE_WARNING_SHADOW \ - _Pragma("GCC diagnostic push"); \ - _Pragma("GCC diagnostic ignored \"-Wshadow\"") - -#define REENABLE_WARNING \ - _Pragma("GCC diagnostic pop") -#else -#define DISABLE_WARNING_DECLARATION_AFTER_STATEMENT -#define DISABLE_WARNING_FORMAT_NONLITERAL -#define DISABLE_WARNING_MISSING_PROTOTYPES -#define DISABLE_WARNING_NONNULL -#define DISABLE_WARNING_SHADOW -#define REENABLE_WARNING -#endif - -/* automake test harness */ -#define EXIT_TEST_SKIP 77 - -#define XSTRINGIFY(x) #x -#define STRINGIFY(x) XSTRINGIFY(x) - -#define XCONCATENATE(x, y) x ## y -#define CONCATENATE(x, y) XCONCATENATE(x, y) - -#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq)) -#define UNIQ __COUNTER__ - -/* Rounds up */ - -#define ALIGN4(l) (((l) + 3) & ~3) -#define ALIGN8(l) (((l) + 7) & ~7) - -#if __SIZEOF_POINTER__ == 8 -#define ALIGN(l) ALIGN8(l) -#elif __SIZEOF_POINTER__ == 4 -#define ALIGN(l) ALIGN4(l) -#else -#error "Wut? Pointers are neither 4 nor 8 bytes long?" -#endif - -#define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) p)) -#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) p)) -#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) p)) - -static inline size_t ALIGN_TO(size_t l, size_t ali) { - return ((l + ali - 1) & ~(ali - 1)); -} - -#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) p, ali)) - -/* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */ -static inline unsigned long ALIGN_POWER2(unsigned long u) { - /* clz(0) is undefined */ - if (u == 1) - return 1; - - /* left-shift overflow is undefined */ - if (__builtin_clzl(u - 1UL) < 1) - return 0; - - return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL)); -} - -#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) - -/* - * container_of - cast a member of a structure out to the containing structure - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - */ -#define container_of(ptr, type, member) __container_of(UNIQ, (ptr), type, member) -#define __container_of(uniq, ptr, type, member) \ - __extension__ ({ \ - const typeof( ((type*)0)->member ) *UNIQ_T(A, uniq) = (ptr); \ - (type*)( (char *)UNIQ_T(A, uniq) - offsetof(type,member) ); \ - }) - -#undef MAX -#define MAX(a, b) __MAX(UNIQ, (a), UNIQ, (b)) -#define __MAX(aq, a, bq, b) \ - __extension__ ({ \ - const typeof(a) UNIQ_T(A, aq) = (a); \ - const typeof(b) UNIQ_T(B, bq) = (b); \ - UNIQ_T(A,aq) > UNIQ_T(B,bq) ? UNIQ_T(A,aq) : UNIQ_T(B,bq); \ - }) - -/* evaluates to (void) if _A or _B are not constant or of different types */ -#define CONST_MAX(_A, _B) \ - __extension__ (__builtin_choose_expr( \ - __builtin_constant_p(_A) && \ - __builtin_constant_p(_B) && \ - __builtin_types_compatible_p(typeof(_A), typeof(_B)), \ - ((_A) > (_B)) ? (_A) : (_B), \ - (void)0)) - -/* takes two types and returns the size of the larger one */ -#define MAXSIZE(A, B) (sizeof(union _packed_ { typeof(A) a; typeof(B) b; })) - -#define MAX3(x,y,z) \ - __extension__ ({ \ - const typeof(x) _c = MAX(x,y); \ - MAX(_c, z); \ - }) - -#undef MIN -#define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b)) -#define __MIN(aq, a, bq, b) \ - __extension__ ({ \ - const typeof(a) UNIQ_T(A, aq) = (a); \ - const typeof(b) UNIQ_T(B, bq) = (b); \ - UNIQ_T(A,aq) < UNIQ_T(B,bq) ? UNIQ_T(A,aq) : UNIQ_T(B,bq); \ - }) - -#define MIN3(x,y,z) \ - __extension__ ({ \ - const typeof(x) _c = MIN(x,y); \ - MIN(_c, z); \ - }) - -#define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b)) -#define __LESS_BY(aq, a, bq, b) \ - __extension__ ({ \ - const typeof(a) UNIQ_T(A, aq) = (a); \ - const typeof(b) UNIQ_T(B, bq) = (b); \ - UNIQ_T(A,aq) > UNIQ_T(B,bq) ? UNIQ_T(A,aq) - UNIQ_T(B,bq) : 0; \ - }) - -#undef CLAMP -#define CLAMP(x, low, high) __CLAMP(UNIQ, (x), UNIQ, (low), UNIQ, (high)) -#define __CLAMP(xq, x, lowq, low, highq, high) \ - __extension__ ({ \ - const typeof(x) UNIQ_T(X,xq) = (x); \ - const typeof(low) UNIQ_T(LOW,lowq) = (low); \ - const typeof(high) UNIQ_T(HIGH,highq) = (high); \ - UNIQ_T(X,xq) > UNIQ_T(HIGH,highq) ? \ - UNIQ_T(HIGH,highq) : \ - UNIQ_T(X,xq) < UNIQ_T(LOW,lowq) ? \ - UNIQ_T(LOW,lowq) : \ - UNIQ_T(X,xq); \ - }) - -#define assert_se(expr) \ - do { \ - if (_unlikely_(!(expr))) \ - log_assert_failed(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - } while (false) \ - -/* We override the glibc assert() here. */ -#undef assert -#ifdef NDEBUG -#define assert(expr) do {} while(false) -#else -#define assert(expr) assert_se(expr) -#endif - -#define assert_not_reached(t) \ - do { \ - log_assert_failed_unreachable(t, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - } while (false) - -#if defined(static_assert) -/* static_assert() is sometimes defined in a way that trips up - * -Wdeclaration-after-statement, hence let's temporarily turn off - * this warning around it. */ -#define assert_cc(expr) \ - DISABLE_WARNING_DECLARATION_AFTER_STATEMENT; \ - static_assert(expr, #expr); \ - REENABLE_WARNING -#else -#define assert_cc(expr) \ - DISABLE_WARNING_DECLARATION_AFTER_STATEMENT; \ - struct CONCATENATE(_assert_struct_, __LINE__) { \ - char x[(expr) ? 0 : -1]; \ - }; \ - REENABLE_WARNING -#endif - -#define assert_return(expr, r) \ - do { \ - if (_unlikely_(!(expr))) { \ - log_assert_failed_return(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ - return (r); \ - } \ - } while (false) - -#define PTR_TO_INT(p) ((int) ((intptr_t) (p))) -#define INT_TO_PTR(u) ((void *) ((intptr_t) (u))) -#define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p))) -#define UINT_TO_PTR(u) ((void *) ((uintptr_t) (u))) - -#define PTR_TO_LONG(p) ((long) ((intptr_t) (p))) -#define LONG_TO_PTR(u) ((void *) ((intptr_t) (u))) -#define PTR_TO_ULONG(p) ((unsigned long) ((uintptr_t) (p))) -#define ULONG_TO_PTR(u) ((void *) ((uintptr_t) (u))) - -#define PTR_TO_INT32(p) ((int32_t) ((intptr_t) (p))) -#define INT32_TO_PTR(u) ((void *) ((intptr_t) (u))) -#define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p))) -#define UINT32_TO_PTR(u) ((void *) ((uintptr_t) (u))) - -#define PTR_TO_INT64(p) ((int64_t) ((intptr_t) (p))) -#define INT64_TO_PTR(u) ((void *) ((intptr_t) (u))) -#define PTR_TO_UINT64(p) ((uint64_t) ((uintptr_t) (p))) -#define UINT64_TO_PTR(u) ((void *) ((uintptr_t) (u))) - -#define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p))) -#define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u))) - -#define memzero(x,l) (memset((x), 0, (l))) -#define zero(x) (memzero(&(x), sizeof(x))) - -#define CHAR_TO_STR(x) ((char[2]) { x, 0 }) - -#define char_array_0(x) x[sizeof(x)-1] = 0; - -#define IOVEC_SET_STRING(i, s) \ - do { \ - struct iovec *_i = &(i); \ - char *_s = (char *)(s); \ - _i->iov_base = _s; \ - _i->iov_len = strlen(_s); \ - } while(false) - -static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { - unsigned j; - size_t r = 0; - - for (j = 0; j < n; j++) - r += i[j].iov_len; - - return r; -} - -static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { - unsigned j; - - for (j = 0; j < n; j++) { - size_t sub; - - if (_unlikely_(k <= 0)) - break; - - sub = MIN(i[j].iov_len, k); - i[j].iov_len -= sub; - i[j].iov_base = (uint8_t*) i[j].iov_base + sub; - k -= sub; - } - - return k; -} - -#define VA_FORMAT_ADVANCE(format, ap) \ -do { \ - int _argtypes[128]; \ - size_t _i, _k; \ - _k = parse_printf_format((format), ELEMENTSOF(_argtypes), _argtypes); \ - assert(_k < ELEMENTSOF(_argtypes)); \ - for (_i = 0; _i < _k; _i++) { \ - if (_argtypes[_i] & PA_FLAG_PTR) { \ - (void) va_arg(ap, void*); \ - continue; \ - } \ - \ - switch (_argtypes[_i]) { \ - case PA_INT: \ - case PA_INT|PA_FLAG_SHORT: \ - case PA_CHAR: \ - (void) va_arg(ap, int); \ - break; \ - case PA_INT|PA_FLAG_LONG: \ - (void) va_arg(ap, long int); \ - break; \ - case PA_INT|PA_FLAG_LONG_LONG: \ - (void) va_arg(ap, long long int); \ - break; \ - case PA_WCHAR: \ - (void) va_arg(ap, wchar_t); \ - break; \ - case PA_WSTRING: \ - case PA_STRING: \ - case PA_POINTER: \ - (void) va_arg(ap, void*); \ - break; \ - case PA_FLOAT: \ - case PA_DOUBLE: \ - (void) va_arg(ap, double); \ - break; \ - case PA_DOUBLE|PA_FLAG_LONG_DOUBLE: \ - (void) va_arg(ap, long double); \ - break; \ - default: \ - assert_not_reached("Unknown format string argument."); \ - } \ - } \ -} while(false) - - /* Because statfs.t_type can be int on some architectures, we have to cast - * the const magic to the type, otherwise the compiler warns about - * signed/unsigned comparison, because the magic can be 32 bit unsigned. - */ -#define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b) - -/* Returns the number of chars needed to format variables of the - * specified type as a decimal string. Adds in extra space for a - * negative '-' prefix. */ -#define DECIMAL_STR_MAX(type) \ - (2+(sizeof(type) <= 1 ? 3 : \ - sizeof(type) <= 2 ? 5 : \ - sizeof(type) <= 4 ? 10 : \ - sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)]))) - -#define SET_FLAG(v, flag, b) \ - (v) = (b) ? ((v) | (flag)) : ((v) & ~(flag)) - -#define IN_SET(x, y, ...) \ - ({ \ - const typeof(y) _y = (y); \ - typeof(_y) _x = (x); \ - unsigned _i; \ - bool _found = false; \ - for (_i = 0; _i < 1 + sizeof((typeof(_x)[]) { __VA_ARGS__ })/sizeof(typeof(_x)); _i++) \ - if (((typeof(_x)[]) { _y, __VA_ARGS__ })[_i] == _x) { \ - _found = true; \ - break; \ - } \ - _found; \ - }) - -#if 0 /* NM_IGNORED */ -/* Define C11 thread_local attribute even on older gcc compiler - * version */ -#ifndef thread_local -/* - * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__ - * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 - */ -#if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16)) -#define thread_local _Thread_local -#else -#define thread_local __thread -#endif -#endif - -/* Define C11 noreturn without and even on older gcc - * compiler versions */ -#ifndef noreturn -#if __STDC_VERSION__ >= 201112L -#define noreturn _Noreturn -#else -#define noreturn __attribute__((noreturn)) -#endif -#endif - -#include "log.h" -#endif diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/refcnt.h b/src/dhcp-manager/systemd-dhcp/src/shared/refcnt.h deleted file mode 100644 index 0502c20a..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/refcnt.h +++ /dev/null @@ -1,34 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -/* A type-safe atomic refcounter */ - -typedef struct { - volatile unsigned _value; -} RefCount; - -#define REFCNT_GET(r) ((r)._value) -#define REFCNT_INC(r) (__sync_add_and_fetch(&(r)._value, 1)) -#define REFCNT_DEC(r) (__sync_sub_and_fetch(&(r)._value, 1)) - -#define REFCNT_INIT ((RefCount) { ._value = 1 }) diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/siphash24.c b/src/dhcp-manager/systemd-dhcp/src/shared/siphash24.c deleted file mode 100644 index f9e59c6f..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/siphash24.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - SipHash reference C implementation - - Written in 2012 by - Jean-Philippe Aumasson - Daniel J. Bernstein - - To the extent possible under law, the author(s) have dedicated all copyright - and related and neighboring rights to this software to the public domain - worldwide. This software is distributed without any warranty. - - You should have received a copy of the CC0 Public Domain Dedication along with - this software. If not, see . - - (Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd) -*/ -#include "config.h" - -#include -#include -#include - -#include "siphash24.h" - -typedef uint64_t u64; -typedef uint32_t u32; -typedef uint8_t u8; - -#define ROTL(x,b) (u64)( ((x) << (b)) | ( (x) >> (64 - (b))) ) - -#define U32TO8_LE(p, v) \ - (p)[0] = (u8)((v) ); (p)[1] = (u8)((v) >> 8); \ - (p)[2] = (u8)((v) >> 16); (p)[3] = (u8)((v) >> 24); - -#define U64TO8_LE(p, v) \ - U32TO8_LE((p), (u32)((v) )); \ - U32TO8_LE((p) + 4, (u32)((v) >> 32)); - -#define U8TO64_LE(p) \ - (((u64)((p)[0]) ) | \ - ((u64)((p)[1]) << 8) | \ - ((u64)((p)[2]) << 16) | \ - ((u64)((p)[3]) << 24) | \ - ((u64)((p)[4]) << 32) | \ - ((u64)((p)[5]) << 40) | \ - ((u64)((p)[6]) << 48) | \ - ((u64)((p)[7]) << 56)) - -#define SIPROUND \ - do { \ - v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \ - v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \ - v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \ - v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \ - } while(0) - -/* SipHash-2-4 */ -void siphash24(uint8_t out[8], const void *_in, size_t inlen, const uint8_t k[16]) -{ - /* "somepseudorandomlygeneratedbytes" */ - u64 v0 = 0x736f6d6570736575ULL; - u64 v1 = 0x646f72616e646f6dULL; - u64 v2 = 0x6c7967656e657261ULL; - u64 v3 = 0x7465646279746573ULL; - u64 b; - u64 k0 = U8TO64_LE( k ); - u64 k1 = U8TO64_LE( k + 8 ); - u64 m; - const u8 *in = _in; - const u8 *end = in + inlen - ( inlen % sizeof( u64 ) ); - const int left = inlen & 7; - b = ( ( u64 )inlen ) << 56; - v3 ^= k1; - v2 ^= k0; - v1 ^= k1; - v0 ^= k0; - - for ( ; in != end; in += 8 ) - { - m = U8TO64_LE( in ); -#ifdef DEBUG - printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); - printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); - printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); - printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); - printf( "(%3d) compress %08x %08x\n", ( int )inlen, ( u32 )( m >> 32 ), ( u32 )m ); -#endif - v3 ^= m; - SIPROUND; - SIPROUND; - v0 ^= m; - } - - switch( left ) - { - case 7: b |= ( ( u64 )in[ 6] ) << 48; - - case 6: b |= ( ( u64 )in[ 5] ) << 40; - - case 5: b |= ( ( u64 )in[ 4] ) << 32; - - case 4: b |= ( ( u64 )in[ 3] ) << 24; - - case 3: b |= ( ( u64 )in[ 2] ) << 16; - - case 2: b |= ( ( u64 )in[ 1] ) << 8; - - case 1: b |= ( ( u64 )in[ 0] ); break; - - case 0: break; - } - -#ifdef DEBUG - printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); - printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); - printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); - printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); - printf( "(%3d) padding %08x %08x\n", ( int )inlen, ( u32 )( b >> 32 ), ( u32 )b ); -#endif - v3 ^= b; - SIPROUND; - SIPROUND; - v0 ^= b; -#ifdef DEBUG - printf( "(%3d) v0 %08x %08x\n", ( int )inlen, ( u32 )( v0 >> 32 ), ( u32 )v0 ); - printf( "(%3d) v1 %08x %08x\n", ( int )inlen, ( u32 )( v1 >> 32 ), ( u32 )v1 ); - printf( "(%3d) v2 %08x %08x\n", ( int )inlen, ( u32 )( v2 >> 32 ), ( u32 )v2 ); - printf( "(%3d) v3 %08x %08x\n", ( int )inlen, ( u32 )( v3 >> 32 ), ( u32 )v3 ); -#endif - v2 ^= 0xff; - SIPROUND; - SIPROUND; - SIPROUND; - SIPROUND; - b = v0 ^ v1 ^ v2 ^ v3; - U64TO8_LE( out, b ); -} diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/siphash24.h b/src/dhcp-manager/systemd-dhcp/src/shared/siphash24.h deleted file mode 100644 index 62e1168a..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/siphash24.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include -#include - -void siphash24(uint8_t out[8], const void *in, size_t inlen, const uint8_t k[16]); diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/socket-util.h b/src/dhcp-manager/systemd-dhcp/src/shared/socket-util.h deleted file mode 100644 index 07d0aff7..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/socket-util.h +++ /dev/null @@ -1,118 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include -#include -#include - -#include "macro.h" -#include "util.h" - -union sockaddr_union { - struct sockaddr sa; - struct sockaddr_in in; - struct sockaddr_in6 in6; - struct sockaddr_un un; - struct sockaddr_nl nl; - struct sockaddr_storage storage; - struct sockaddr_ll ll; -}; - -typedef struct SocketAddress { - union sockaddr_union sockaddr; - - /* We store the size here explicitly due to the weird - * sockaddr_un semantics for abstract sockets */ - socklen_t size; - - /* Socket type, i.e. SOCK_STREAM, SOCK_DGRAM, ... */ - int type; - - /* Socket protocol, IPPROTO_xxx, usually 0, except for netlink */ - int protocol; -} SocketAddress; - -typedef enum SocketAddressBindIPv6Only { - SOCKET_ADDRESS_DEFAULT, - SOCKET_ADDRESS_BOTH, - SOCKET_ADDRESS_IPV6_ONLY, - _SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX, - _SOCKET_ADDRESS_BIND_IPV6_ONLY_INVALID = -1 -} SocketAddressBindIPv6Only; - -#define socket_address_family(a) ((a)->sockaddr.sa.sa_family) - -int socket_address_parse(SocketAddress *a, const char *s); -int socket_address_parse_netlink(SocketAddress *a, const char *s); -int socket_address_print(const SocketAddress *a, char **p); -int socket_address_verify(const SocketAddress *a) _pure_; -int socket_address_unlink(SocketAddress *a); - -bool socket_address_can_accept(const SocketAddress *a) _pure_; - -int socket_address_listen( - const SocketAddress *a, - int flags, - int backlog, - SocketAddressBindIPv6Only only, - const char *bind_to_device, - bool free_bind, - bool transparent, - mode_t directory_mode, - mode_t socket_mode, - const char *label); -int make_socket_fd(int log_level, const char* address, int flags); - -bool socket_address_is(const SocketAddress *a, const char *s, int type); -bool socket_address_is_netlink(const SocketAddress *a, const char *s); - -bool socket_address_matches_fd(const SocketAddress *a, int fd); - -bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) _pure_; - -const char* socket_address_get_path(const SocketAddress *a); - -bool socket_ipv6_is_supported(void); - -int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, char **ret); -int getpeername_pretty(int fd, char **ret); -int getsockname_pretty(int fd, char **ret); - -int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret); -int getnameinfo_pretty(int fd, char **ret); - -const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b) _const_; -SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s) _pure_; - -int netlink_family_to_string_alloc(int b, char **s); -int netlink_family_from_string(const char *s) _pure_; - -bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b); - -#define ETHER_ADDR_TO_STRING_MAX (3*6) - -char* ether_addr_to_string(const struct ether_addr *addr, char buffer[ETHER_ADDR_TO_STRING_MAX]); diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/sparse-endian.h b/src/dhcp-manager/systemd-dhcp/src/shared/sparse-endian.h deleted file mode 100644 index c913fda8..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/sparse-endian.h +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (c) 2012 Josh Triplett - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#ifndef SPARSE_ENDIAN_H -#define SPARSE_ENDIAN_H - -#include -#include -#include - -#ifdef __CHECKER__ -#define __bitwise __attribute__((bitwise)) -#define __force __attribute__((force)) -#else -#define __bitwise -#define __force -#endif - -typedef uint16_t __bitwise le16_t; -typedef uint16_t __bitwise be16_t; -typedef uint32_t __bitwise le32_t; -typedef uint32_t __bitwise be32_t; -typedef uint64_t __bitwise le64_t; -typedef uint64_t __bitwise be64_t; - -#undef htobe16 -#undef htole16 -#undef be16toh -#undef le16toh -#undef htobe32 -#undef htole32 -#undef be32toh -#undef le32toh -#undef htobe64 -#undef htole64 -#undef be64toh -#undef le64toh - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define bswap_16_on_le(x) __bswap_16(x) -#define bswap_32_on_le(x) __bswap_32(x) -#define bswap_64_on_le(x) __bswap_64(x) -#define bswap_16_on_be(x) (x) -#define bswap_32_on_be(x) (x) -#define bswap_64_on_be(x) (x) -#elif __BYTE_ORDER == __BIG_ENDIAN -#define bswap_16_on_le(x) (x) -#define bswap_32_on_le(x) (x) -#define bswap_64_on_le(x) (x) -#define bswap_16_on_be(x) __bswap_16(x) -#define bswap_32_on_be(x) __bswap_32(x) -#define bswap_64_on_be(x) __bswap_64(x) -#endif - -static inline le16_t htole16(uint16_t value) { return (le16_t __force) bswap_16_on_be(value); } -static inline le32_t htole32(uint32_t value) { return (le32_t __force) bswap_32_on_be(value); } -static inline le64_t htole64(uint64_t value) { return (le64_t __force) bswap_64_on_be(value); } - -static inline be16_t htobe16(uint16_t value) { return (be16_t __force) bswap_16_on_le(value); } -static inline be32_t htobe32(uint32_t value) { return (be32_t __force) bswap_32_on_le(value); } -static inline be64_t htobe64(uint64_t value) { return (be64_t __force) bswap_64_on_le(value); } - -static inline uint16_t le16toh(le16_t value) { return bswap_16_on_be((uint16_t __force)value); } -static inline uint32_t le32toh(le32_t value) { return bswap_32_on_be((uint32_t __force)value); } -static inline uint64_t le64toh(le64_t value) { return bswap_64_on_be((uint64_t __force)value); } - -static inline uint16_t be16toh(be16_t value) { return bswap_16_on_le((uint16_t __force)value); } -static inline uint32_t be32toh(be32_t value) { return bswap_32_on_le((uint32_t __force)value); } -static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t __force)value); } - -#endif /* SPARSE_ENDIAN_H */ diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/strv.c b/src/dhcp-manager/systemd-dhcp/src/shared/strv.c deleted file mode 100644 index be2bd511..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/strv.c +++ /dev/null @@ -1,616 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "config.h" - -#include "nm-sd-adapt.h" - -#include -#include -#include -#include -#include - -#include "util.h" -#include "strv.h" - -char *strv_find(char **l, const char *name) { - char **i; - - assert(name); - - STRV_FOREACH(i, l) - if (streq(*i, name)) - return *i; - - return NULL; -} - -char *strv_find_prefix(char **l, const char *name) { - char **i; - - assert(name); - - STRV_FOREACH(i, l) - if (startswith(*i, name)) - return *i; - - return NULL; -} - -char *strv_find_startswith(char **l, const char *name) { - char **i, *e; - - assert(name); - - /* Like strv_find_prefix, but actually returns only the - * suffix, not the whole item */ - - STRV_FOREACH(i, l) { - e = startswith(*i, name); - if (e) - return e; - } - - return NULL; -} - -void strv_free(char **l) { - char **k; - - if (!l) - return; - - for (k = l; *k; k++) - free(*k); - - free(l); -} - -char **strv_copy(char * const *l) { - char **r, **k; - - k = r = new(char*, strv_length(l) + 1); - if (!r) - return NULL; - - if (l) - for (; *l; k++, l++) { - *k = strdup(*l); - if (!*k) { - strv_free(r); - return NULL; - } - } - - *k = NULL; - return r; -} - -unsigned strv_length(char * const *l) { - unsigned n = 0; - - if (!l) - return 0; - - for (; *l; l++) - n++; - - return n; -} - -char **strv_new_ap(const char *x, va_list ap) { - const char *s; - char **a; - unsigned n = 0, i = 0; - va_list aq; - - /* As a special trick we ignore all listed strings that equal - * (const char*) -1. This is supposed to be used with the - * STRV_IFNOTNULL() macro to include possibly NULL strings in - * the string list. */ - - if (x) { - n = x == (const char*) -1 ? 0 : 1; - - va_copy(aq, ap); - while ((s = va_arg(aq, const char*))) { - if (s == (const char*) -1) - continue; - - n++; - } - - va_end(aq); - } - - a = new(char*, n+1); - if (!a) - return NULL; - - if (x) { - if (x != (const char*) -1) { - a[i] = strdup(x); - if (!a[i]) - goto fail; - i++; - } - - while ((s = va_arg(ap, const char*))) { - - if (s == (const char*) -1) - continue; - - a[i] = strdup(s); - if (!a[i]) - goto fail; - - i++; - } - } - - a[i] = NULL; - - return a; - -fail: - strv_free(a); - return NULL; -} - -char **strv_new(const char *x, ...) { - char **r; - va_list ap; - - va_start(ap, x); - r = strv_new_ap(x, ap); - va_end(ap); - - return r; -} - -int strv_extend_strv(char ***a, char **b) { - int r; - char **s; - - STRV_FOREACH(s, b) { - r = strv_extend(a, *s); - if (r < 0) - return r; - } - - return 0; -} - -int strv_extend_strv_concat(char ***a, char **b, const char *suffix) { - int r; - char **s; - - STRV_FOREACH(s, b) { - char *v; - - v = strappend(*s, suffix); - if (!v) - return -ENOMEM; - - r = strv_push(a, v); - if (r < 0) { - free(v); - return r; - } - } - - return 0; -} - -char **strv_split(const char *s, const char *separator) { - const char *word, *state; - size_t l; - unsigned n, i; - char **r; - - assert(s); - - n = 0; - FOREACH_WORD_SEPARATOR(word, l, s, separator, state) - n++; - - r = new(char*, n+1); - if (!r) - return NULL; - - i = 0; - FOREACH_WORD_SEPARATOR(word, l, s, separator, state) { - r[i] = strndup(word, l); - if (!r[i]) { - strv_free(r); - return NULL; - } - - i++; - } - - r[i] = NULL; - return r; -} - -char **strv_split_newlines(const char *s) { - char **l; - unsigned n; - - assert(s); - - /* Special version of strv_split() that splits on newlines and - * suppresses an empty string at the end */ - - l = strv_split(s, NEWLINE); - if (!l) - return NULL; - - n = strv_length(l); - if (n <= 0) - return l; - - if (isempty(l[n-1])) { - free(l[n-1]); - l[n-1] = NULL; - } - - return l; -} - -#if 0 /* NM_IGNORED */ -int strv_split_quoted(char ***t, const char *s, bool relax) { - size_t n = 0, allocated = 0; - _cleanup_strv_free_ char **l = NULL; - int r; - - assert(t); - assert(s); - - for (;;) { - _cleanup_free_ char *word = NULL; - - r = unquote_first_word(&s, &word, relax); - if (r < 0) - return r; - if (r == 0) - break; - - if (!GREEDY_REALLOC(l, allocated, n + 2)) - return -ENOMEM; - - l[n++] = word; - word = NULL; - - l[n] = NULL; - } - - if (!l) - l = new0(char*, 1); - - *t = l; - l = NULL; - - return 0; -} -#endif - -char *strv_join(char **l, const char *separator) { - char *r, *e; - char **s; - size_t n, k; - - if (!separator) - separator = " "; - - k = strlen(separator); - - n = 0; - STRV_FOREACH(s, l) { - if (n != 0) - n += k; - n += strlen(*s); - } - - r = new(char, n+1); - if (!r) - return NULL; - - e = r; - STRV_FOREACH(s, l) { - if (e != r) - e = stpcpy(e, separator); - - e = stpcpy(e, *s); - } - - *e = 0; - - return r; -} - -char *strv_join_quoted(char **l) { - char *buf = NULL; - char **s; - size_t allocated = 0, len = 0; - - STRV_FOREACH(s, l) { - /* assuming here that escaped string cannot be more - * than twice as long, and reserving space for the - * separator and quotes. - */ - _cleanup_free_ char *esc = NULL; - size_t needed; - - if (!GREEDY_REALLOC(buf, allocated, - len + strlen(*s) * 2 + 3)) - goto oom; - - esc = cescape(*s); - if (!esc) - goto oom; - - needed = snprintf(buf + len, allocated - len, "%s\"%s\"", - len > 0 ? " " : "", esc); - assert(needed < allocated - len); - len += needed; - } - - if (!buf) - buf = malloc0(1); - - return buf; - - oom: - free(buf); - return NULL; -} - -int strv_push(char ***l, char *value) { - char **c; - unsigned n, m; - - if (!value) - return 0; - - n = strv_length(*l); - - /* increase and check for overflow */ - m = n + 2; - if (m < n) - return -ENOMEM; - - c = realloc_multiply(*l, sizeof(char*), m); - if (!c) - return -ENOMEM; - - c[n] = value; - c[n+1] = NULL; - - *l = c; - return 0; -} - -int strv_push_prepend(char ***l, char *value) { - char **c; - unsigned n, m, i; - - if (!value) - return 0; - - n = strv_length(*l); - - /* increase and check for overflow */ - m = n + 2; - if (m < n) - return -ENOMEM; - - c = new(char*, m); - if (!c) - return -ENOMEM; - - for (i = 0; i < n; i++) - c[i+1] = (*l)[i]; - - c[0] = value; - c[n+1] = NULL; - - free(*l); - *l = c; - - return 0; -} - -int strv_consume(char ***l, char *value) { - int r; - - r = strv_push(l, value); - if (r < 0) - free(value); - - return r; -} - -int strv_consume_prepend(char ***l, char *value) { - int r; - - r = strv_push_prepend(l, value); - if (r < 0) - free(value); - - return r; -} - -int strv_extend(char ***l, const char *value) { - char *v; - - if (!value) - return 0; - - v = strdup(value); - if (!v) - return -ENOMEM; - - return strv_consume(l, v); -} - -char **strv_uniq(char **l) { - char **i; - - /* Drops duplicate entries. The first identical string will be - * kept, the others dropped */ - - STRV_FOREACH(i, l) - strv_remove(i+1, *i); - - return l; -} - -char **strv_remove(char **l, const char *s) { - char **f, **t; - - if (!l) - return NULL; - - assert(s); - - /* Drops every occurrence of s in the string list, edits - * in-place. */ - - for (f = t = l; *f; f++) - if (streq(*f, s)) - free(*f); - else - *(t++) = *f; - - *t = NULL; - return l; -} - -char **strv_parse_nulstr(const char *s, size_t l) { - const char *p; - unsigned c = 0, i = 0; - char **v; - - assert(s || l <= 0); - - if (l <= 0) - return new0(char*, 1); - - for (p = s; p < s + l; p++) - if (*p == 0) - c++; - - if (s[l-1] != 0) - c++; - - v = new0(char*, c+1); - if (!v) - return NULL; - - p = s; - while (p < s + l) { - const char *e; - - e = memchr(p, 0, s + l - p); - - v[i] = strndup(p, e ? e - p : s + l - p); - if (!v[i]) { - strv_free(v); - return NULL; - } - - i++; - - if (!e) - break; - - p = e + 1; - } - - assert(i == c); - - return v; -} - -char **strv_split_nulstr(const char *s) { - const char *i; - char **r = NULL; - - NULSTR_FOREACH(i, s) - if (strv_extend(&r, i) < 0) { - strv_free(r); - return NULL; - } - - if (!r) - return strv_new(NULL, NULL); - - return r; -} - -bool strv_overlap(char **a, char **b) { - char **i; - - STRV_FOREACH(i, a) - if (strv_contains(b, *i)) - return true; - - return false; -} - -static int str_compare(const void *_a, const void *_b) { - const char **a = (const char**) _a, **b = (const char**) _b; - - return strcmp(*a, *b); -} - -char **strv_sort(char **l) { - - if (strv_isempty(l)) - return l; - - qsort(l, strv_length(l), sizeof(char*), str_compare); - return l; -} - -void strv_print(char **l) { - char **s; - - STRV_FOREACH(s, l) - puts(*s); -} - -int strv_extendf(char ***l, const char *format, ...) { - va_list ap; - char *x; - int r; - - va_start(ap, format); - r = vasprintf(&x, format, ap); - va_end(ap); - - if (r < 0) - return -ENOMEM; - - return strv_consume(l, x); -} diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/strv.h b/src/dhcp-manager/systemd-dhcp/src/shared/strv.h deleted file mode 100644 index 47618bd2..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/strv.h +++ /dev/null @@ -1,137 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "util.h" - -char *strv_find(char **l, const char *name) _pure_; -char *strv_find_prefix(char **l, const char *name) _pure_; -char *strv_find_startswith(char **l, const char *name) _pure_; - -void strv_free(char **l); -DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free); -#define _cleanup_strv_free_ _cleanup_(strv_freep) - -char **strv_copy(char * const *l); -unsigned strv_length(char * const *l) _pure_; - -int strv_extend_strv(char ***a, char **b); -int strv_extend_strv_concat(char ***a, char **b, const char *suffix); -int strv_extend(char ***l, const char *value); -int strv_extendf(char ***l, const char *format, ...) _printf_(2,0); -int strv_push(char ***l, char *value); -int strv_push_prepend(char ***l, char *value); -int strv_consume(char ***l, char *value); -int strv_consume_prepend(char ***l, char *value); - -char **strv_remove(char **l, const char *s); -char **strv_uniq(char **l); - -#define strv_contains(l, s) (!!strv_find((l), (s))) - -char **strv_new(const char *x, ...) _sentinel_; -char **strv_new_ap(const char *x, va_list ap); - -static inline const char* STRV_IFNOTNULL(const char *x) { - return x ? x : (const char *) -1; -} - -static inline bool strv_isempty(char * const *l) { - return !l || !*l; -} - -char **strv_split(const char *s, const char *separator); -char **strv_split_newlines(const char *s); - -int strv_split_quoted(char ***t, const char *s, bool relax); - -char *strv_join(char **l, const char *separator); -char *strv_join_quoted(char **l); - -char **strv_parse_nulstr(const char *s, size_t l); -char **strv_split_nulstr(const char *s); - -bool strv_overlap(char **a, char **b) _pure_; - -#define STRV_FOREACH(s, l) \ - for ((s) = (l); (s) && *(s); (s)++) - -#define STRV_FOREACH_BACKWARDS(s, l) \ - STRV_FOREACH(s, l) \ - ; \ - for ((s)--; (l) && ((s) >= (l)); (s)--) - -#define STRV_FOREACH_PAIR(x, y, l) \ - for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1)) - -char **strv_sort(char **l); -void strv_print(char **l); - -#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL })) - -#define STRV_MAKE_EMPTY ((char*[1]) { NULL }) - -#define strv_from_stdarg_alloca(first) \ - ({ \ - char **_l; \ - \ - if (!first) \ - _l = (char**) &first; \ - else { \ - unsigned _n; \ - va_list _ap; \ - \ - _n = 1; \ - va_start(_ap, first); \ - while (va_arg(_ap, char*)) \ - _n++; \ - va_end(_ap); \ - \ - _l = newa(char*, _n+1); \ - _l[_n = 0] = (char*) first; \ - va_start(_ap, first); \ - for (;;) { \ - _l[++_n] = va_arg(_ap, char*); \ - if (!_l[_n]) \ - break; \ - } \ - va_end(_ap); \ - } \ - _l; \ - }) - -#define STR_IN_SET(x, ...) strv_contains(STRV_MAKE(__VA_ARGS__), x) - -#define FOREACH_STRING(x, ...) \ - for (char **_l = ({ \ - char **_ll = STRV_MAKE(__VA_ARGS__); \ - x = _ll ? _ll[0] : NULL; \ - _ll; \ - }); \ - _l && *_l; \ - x = ({ \ - _l ++; \ - _l[0]; \ - })) diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/time-util.c b/src/dhcp-manager/systemd-dhcp/src/shared/time-util.c deleted file mode 100644 index c8fa1acb..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/time-util.c +++ /dev/null @@ -1,1003 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "config.h" - -#include "nm-sd-adapt.h" - -#include -#include -#include -#include - -#include "util.h" -#include "time-util.h" -#if 0 /* NM_IGNORED */ -#include "strv.h" -#endif - -usec_t now(clockid_t clock_id) { - struct timespec ts; - - assert_se(clock_gettime(clock_id, &ts) == 0); - - return timespec_load(&ts); -} - -dual_timestamp* dual_timestamp_get(dual_timestamp *ts) { - assert(ts); - - ts->realtime = now(CLOCK_REALTIME); - ts->monotonic = now(CLOCK_MONOTONIC); - - return ts; -} - -dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) { - int64_t delta; - assert(ts); - - if (u == USEC_INFINITY || u <= 0) { - ts->realtime = ts->monotonic = u; - return ts; - } - - ts->realtime = u; - - delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u; - ts->monotonic = now(CLOCK_MONOTONIC); - - if ((int64_t) ts->monotonic > delta) - ts->monotonic -= delta; - else - ts->monotonic = 0; - - return ts; -} - -dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) { - int64_t delta; - assert(ts); - - if (u == USEC_INFINITY) { - ts->realtime = ts->monotonic = USEC_INFINITY; - return ts; - } - - ts->monotonic = u; - delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u; - - ts->realtime = now(CLOCK_REALTIME); - if ((int64_t) ts->realtime > delta) - ts->realtime -= delta; - else - ts->realtime = 0; - - return ts; -} - -usec_t timespec_load(const struct timespec *ts) { - assert(ts); - - if (ts->tv_sec == (time_t) -1 && - ts->tv_nsec == (long) -1) - return USEC_INFINITY; - - if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) - return USEC_INFINITY; - - return - (usec_t) ts->tv_sec * USEC_PER_SEC + - (usec_t) ts->tv_nsec / NSEC_PER_USEC; -} - -struct timespec *timespec_store(struct timespec *ts, usec_t u) { - assert(ts); - - if (u == USEC_INFINITY) { - ts->tv_sec = (time_t) -1; - ts->tv_nsec = (long) -1; - return ts; - } - - ts->tv_sec = (time_t) (u / USEC_PER_SEC); - ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC); - - return ts; -} - -#if 0 /* NM_IGNORED */ -usec_t timeval_load(const struct timeval *tv) { - assert(tv); - - if (tv->tv_sec == (time_t) -1 && - tv->tv_usec == (suseconds_t) -1) - return USEC_INFINITY; - - if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC) - return USEC_INFINITY; - - return - (usec_t) tv->tv_sec * USEC_PER_SEC + - (usec_t) tv->tv_usec; -} - -struct timeval *timeval_store(struct timeval *tv, usec_t u) { - assert(tv); - - if (u == USEC_INFINITY) { - tv->tv_sec = (time_t) -1; - tv->tv_usec = (suseconds_t) -1; - } else { - tv->tv_sec = (time_t) (u / USEC_PER_SEC); - tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC); - } - - return tv; -} - -static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) { - struct tm tm; - time_t sec; - - assert(buf); - assert(l > 0); - - if (t <= 0 || t == USEC_INFINITY) - return NULL; - - sec = (time_t) (t / USEC_PER_SEC); - - if (utc) - gmtime_r(&sec, &tm); - else - localtime_r(&sec, &tm); - if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0) - return NULL; - - return buf; -} - -char *format_timestamp(char *buf, size_t l, usec_t t) { - return format_timestamp_internal(buf, l, t, false); -} - -char *format_timestamp_utc(char *buf, size_t l, usec_t t) { - return format_timestamp_internal(buf, l, t, true); -} - -static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool utc) { - struct tm tm; - time_t sec; - - assert(buf); - assert(l > 0); - - if (t <= 0 || t == USEC_INFINITY) - return NULL; - - sec = (time_t) (t / USEC_PER_SEC); - if (utc) - gmtime_r(&sec, &tm); - else - localtime_r(&sec, &tm); - - if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0) - return NULL; - snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC)); - if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0) - return NULL; - - return buf; -} - -char *format_timestamp_us(char *buf, size_t l, usec_t t) { - return format_timestamp_internal_us(buf, l, t, false); -} - -char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) { - return format_timestamp_internal_us(buf, l, t, true); -} - -char *format_timestamp_relative(char *buf, size_t l, usec_t t) { - const char *s; - usec_t n, d; - - if (t <= 0 || t == USEC_INFINITY) - return NULL; - - n = now(CLOCK_REALTIME); - if (n > t) { - d = n - t; - s = "ago"; - } else { - d = t - n; - s = "left"; - } - - if (d >= USEC_PER_YEAR) - snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s", - d / USEC_PER_YEAR, - (d % USEC_PER_YEAR) / USEC_PER_MONTH, s); - else if (d >= USEC_PER_MONTH) - snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s", - d / USEC_PER_MONTH, - (d % USEC_PER_MONTH) / USEC_PER_DAY, s); - else if (d >= USEC_PER_WEEK) - snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s", - d / USEC_PER_WEEK, - (d % USEC_PER_WEEK) / USEC_PER_DAY, s); - else if (d >= 2*USEC_PER_DAY) - snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s); - else if (d >= 25*USEC_PER_HOUR) - snprintf(buf, l, "1 day " USEC_FMT "h %s", - (d - USEC_PER_DAY) / USEC_PER_HOUR, s); - else if (d >= 6*USEC_PER_HOUR) - snprintf(buf, l, USEC_FMT "h %s", - d / USEC_PER_HOUR, s); - else if (d >= USEC_PER_HOUR) - snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s", - d / USEC_PER_HOUR, - (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s); - else if (d >= 5*USEC_PER_MINUTE) - snprintf(buf, l, USEC_FMT "min %s", - d / USEC_PER_MINUTE, s); - else if (d >= USEC_PER_MINUTE) - snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s", - d / USEC_PER_MINUTE, - (d % USEC_PER_MINUTE) / USEC_PER_SEC, s); - else if (d >= USEC_PER_SEC) - snprintf(buf, l, USEC_FMT "s %s", - d / USEC_PER_SEC, s); - else if (d >= USEC_PER_MSEC) - snprintf(buf, l, USEC_FMT "ms %s", - d / USEC_PER_MSEC, s); - else if (d > 0) - snprintf(buf, l, USEC_FMT"us %s", - d, s); - else - snprintf(buf, l, "now"); - - buf[l-1] = 0; - return buf; -} -#endif - -char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { - static const struct { - const char *suffix; - usec_t usec; - } table[] = { - { "y", USEC_PER_YEAR }, - { "month", USEC_PER_MONTH }, - { "w", USEC_PER_WEEK }, - { "d", USEC_PER_DAY }, - { "h", USEC_PER_HOUR }, - { "min", USEC_PER_MINUTE }, - { "s", USEC_PER_SEC }, - { "ms", USEC_PER_MSEC }, - { "us", 1 }, - }; - - unsigned i; - char *p = buf; - bool something = false; - - assert(buf); - assert(l > 0); - - if (t == USEC_INFINITY) { - strncpy(p, "infinity", l-1); - p[l-1] = 0; - return p; - } - - if (t <= 0) { - strncpy(p, "0", l-1); - p[l-1] = 0; - return p; - } - - /* The result of this function can be parsed with parse_sec */ - - for (i = 0; i < ELEMENTSOF(table); i++) { - int k = 0; - size_t n; - bool done = false; - usec_t a, b; - - if (t <= 0) - break; - - if (t < accuracy && something) - break; - - if (t < table[i].usec) - continue; - - if (l <= 1) - break; - - a = t / table[i].usec; - b = t % table[i].usec; - - /* Let's see if we should shows this in dot notation */ - if (t < USEC_PER_MINUTE && b > 0) { - usec_t cc; - int j; - - j = 0; - for (cc = table[i].usec; cc > 1; cc /= 10) - j++; - - for (cc = accuracy; cc > 1; cc /= 10) { - b /= 10; - j--; - } - - if (j > 0) { - k = snprintf(p, l, - "%s"USEC_FMT".%0*llu%s", - p > buf ? " " : "", - a, - j, - (unsigned long long) b, - table[i].suffix); - - t = 0; - done = true; - } - } - - /* No? Then let's show it normally */ - if (!done) { - k = snprintf(p, l, - "%s"USEC_FMT"%s", - p > buf ? " " : "", - a, - table[i].suffix); - - t = b; - } - - n = MIN((size_t) k, l); - - l -= n; - p += n; - - something = true; - } - - *p = 0; - - return buf; -} - -#if 0 /* NM_IGNORED */ -void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) { - - assert(f); - assert(name); - assert(t); - - if (!dual_timestamp_is_set(t)) - return; - - fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n", - name, - t->realtime, - t->monotonic); -} - -void dual_timestamp_deserialize(const char *value, dual_timestamp *t) { - unsigned long long a, b; - - assert(value); - assert(t); - - if (sscanf(value, "%llu %llu", &a, &b) != 2) - log_debug("Failed to parse finish timestamp value %s", value); - else { - t->realtime = a; - t->monotonic = b; - } -} - -int parse_timestamp(const char *t, usec_t *usec) { - static const struct { - const char *name; - const int nr; - } day_nr[] = { - { "Sunday", 0 }, - { "Sun", 0 }, - { "Monday", 1 }, - { "Mon", 1 }, - { "Tuesday", 2 }, - { "Tue", 2 }, - { "Wednesday", 3 }, - { "Wed", 3 }, - { "Thursday", 4 }, - { "Thu", 4 }, - { "Friday", 5 }, - { "Fri", 5 }, - { "Saturday", 6 }, - { "Sat", 6 }, - }; - - const char *k; - struct tm tm, copy; - time_t x; - usec_t plus = 0, minus = 0, ret; - int r, weekday = -1; - unsigned i; - - /* - * Allowed syntaxes: - * - * 2012-09-22 16:34:22 - * 2012-09-22 16:34 (seconds will be set to 0) - * 2012-09-22 (time will be set to 00:00:00) - * 16:34:22 (date will be set to today) - * 16:34 (date will be set to today, seconds to 0) - * now - * yesterday (time is set to 00:00:00) - * today (time is set to 00:00:00) - * tomorrow (time is set to 00:00:00) - * +5min - * -5days - * @2147483647 (seconds since epoch) - * - */ - - assert(t); - assert(usec); - - x = time(NULL); - assert_se(localtime_r(&x, &tm)); - tm.tm_isdst = -1; - - if (streq(t, "now")) - goto finish; - - else if (streq(t, "today")) { - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - - } else if (streq(t, "yesterday")) { - tm.tm_mday --; - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - - } else if (streq(t, "tomorrow")) { - tm.tm_mday ++; - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - - } else if (t[0] == '+') { - r = parse_sec(t+1, &plus); - if (r < 0) - return r; - - goto finish; - - } else if (t[0] == '-') { - r = parse_sec(t+1, &minus); - if (r < 0) - return r; - - goto finish; - - } else if (t[0] == '@') - return parse_sec(t + 1, usec); - - else if (endswith(t, " ago")) { - _cleanup_free_ char *z = strndup(t, strlen(t) - 4); - - if (!z) - return -ENOMEM; - - r = parse_sec(z, &minus); - if (r < 0) - return r; - - goto finish; - } else if (endswith(t, " left")) { - _cleanup_free_ char *z = strndup(t, strlen(t) - 4); - - if (!z) - return -ENOMEM; - - r = parse_sec(z, &plus); - if (r < 0) - return r; - - goto finish; - } - - for (i = 0; i < ELEMENTSOF(day_nr); i++) { - size_t skip; - - if (!startswith_no_case(t, day_nr[i].name)) - continue; - - skip = strlen(day_nr[i].name); - if (t[skip] != ' ') - continue; - - weekday = day_nr[i].nr; - t += skip + 1; - break; - } - - copy = tm; - k = strptime(t, "%y-%m-%d %H:%M:%S", &tm); - if (k && *k == 0) - goto finish; - - tm = copy; - k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm); - if (k && *k == 0) - goto finish; - - tm = copy; - k = strptime(t, "%y-%m-%d %H:%M", &tm); - if (k && *k == 0) { - tm.tm_sec = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%Y-%m-%d %H:%M", &tm); - if (k && *k == 0) { - tm.tm_sec = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%y-%m-%d", &tm); - if (k && *k == 0) { - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%Y-%m-%d", &tm); - if (k && *k == 0) { - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - goto finish; - } - - tm = copy; - k = strptime(t, "%H:%M:%S", &tm); - if (k && *k == 0) - goto finish; - - tm = copy; - k = strptime(t, "%H:%M", &tm); - if (k && *k == 0) { - tm.tm_sec = 0; - goto finish; - } - - return -EINVAL; - -finish: - x = mktime(&tm); - if (x == (time_t) -1) - return -EINVAL; - - if (weekday >= 0 && tm.tm_wday != weekday) - return -EINVAL; - - ret = (usec_t) x * USEC_PER_SEC; - - ret += plus; - if (ret > minus) - ret -= minus; - else - ret = 0; - - *usec = ret; - - return 0; -} - -int parse_sec(const char *t, usec_t *usec) { - static const struct { - const char *suffix; - usec_t usec; - } table[] = { - { "seconds", USEC_PER_SEC }, - { "second", USEC_PER_SEC }, - { "sec", USEC_PER_SEC }, - { "s", USEC_PER_SEC }, - { "minutes", USEC_PER_MINUTE }, - { "minute", USEC_PER_MINUTE }, - { "min", USEC_PER_MINUTE }, - { "months", USEC_PER_MONTH }, - { "month", USEC_PER_MONTH }, - { "msec", USEC_PER_MSEC }, - { "ms", USEC_PER_MSEC }, - { "m", USEC_PER_MINUTE }, - { "hours", USEC_PER_HOUR }, - { "hour", USEC_PER_HOUR }, - { "hr", USEC_PER_HOUR }, - { "h", USEC_PER_HOUR }, - { "days", USEC_PER_DAY }, - { "day", USEC_PER_DAY }, - { "d", USEC_PER_DAY }, - { "weeks", USEC_PER_WEEK }, - { "week", USEC_PER_WEEK }, - { "w", USEC_PER_WEEK }, - { "years", USEC_PER_YEAR }, - { "year", USEC_PER_YEAR }, - { "y", USEC_PER_YEAR }, - { "usec", 1ULL }, - { "us", 1ULL }, - { "", USEC_PER_SEC }, /* default is sec */ - }; - - const char *p, *s; - usec_t r = 0; - bool something = false; - - assert(t); - assert(usec); - - p = t; - - p += strspn(p, WHITESPACE); - s = startswith(p, "infinity"); - if (s) { - s += strspn(s, WHITESPACE); - if (*s != 0) - return -EINVAL; - - *usec = USEC_INFINITY; - return 0; - } - - for (;;) { - long long l, z = 0; - char *e; - unsigned i, n = 0; - - p += strspn(p, WHITESPACE); - - if (*p == 0) { - if (!something) - return -EINVAL; - - break; - } - - errno = 0; - l = strtoll(p, &e, 10); - - if (errno > 0) - return -errno; - - if (l < 0) - return -ERANGE; - - if (*e == '.') { - char *b = e + 1; - - errno = 0; - z = strtoll(b, &e, 10); - if (errno > 0) - return -errno; - - if (z < 0) - return -ERANGE; - - if (e == b) - return -EINVAL; - - n = e - b; - - } else if (e == p) - return -EINVAL; - - e += strspn(e, WHITESPACE); - - for (i = 0; i < ELEMENTSOF(table); i++) - if (startswith(e, table[i].suffix)) { - usec_t k = (usec_t) z * table[i].usec; - - for (; n > 0; n--) - k /= 10; - - r += (usec_t) l * table[i].usec + k; - p = e + strlen(table[i].suffix); - - something = true; - break; - } - - if (i >= ELEMENTSOF(table)) - return -EINVAL; - - } - - *usec = r; - - return 0; -} - -int parse_nsec(const char *t, nsec_t *nsec) { - static const struct { - const char *suffix; - nsec_t nsec; - } table[] = { - { "seconds", NSEC_PER_SEC }, - { "second", NSEC_PER_SEC }, - { "sec", NSEC_PER_SEC }, - { "s", NSEC_PER_SEC }, - { "minutes", NSEC_PER_MINUTE }, - { "minute", NSEC_PER_MINUTE }, - { "min", NSEC_PER_MINUTE }, - { "months", NSEC_PER_MONTH }, - { "month", NSEC_PER_MONTH }, - { "msec", NSEC_PER_MSEC }, - { "ms", NSEC_PER_MSEC }, - { "m", NSEC_PER_MINUTE }, - { "hours", NSEC_PER_HOUR }, - { "hour", NSEC_PER_HOUR }, - { "hr", NSEC_PER_HOUR }, - { "h", NSEC_PER_HOUR }, - { "days", NSEC_PER_DAY }, - { "day", NSEC_PER_DAY }, - { "d", NSEC_PER_DAY }, - { "weeks", NSEC_PER_WEEK }, - { "week", NSEC_PER_WEEK }, - { "w", NSEC_PER_WEEK }, - { "years", NSEC_PER_YEAR }, - { "year", NSEC_PER_YEAR }, - { "y", NSEC_PER_YEAR }, - { "usec", NSEC_PER_USEC }, - { "us", NSEC_PER_USEC }, - { "nsec", 1ULL }, - { "ns", 1ULL }, - { "", 1ULL }, /* default is nsec */ - }; - - const char *p, *s; - nsec_t r = 0; - bool something = false; - - assert(t); - assert(nsec); - - p = t; - - p += strspn(p, WHITESPACE); - s = startswith(p, "infinity"); - if (s) { - s += strspn(s, WHITESPACE); - if (!*s != 0) - return -EINVAL; - - *nsec = NSEC_INFINITY; - return 0; - } - - for (;;) { - long long l, z = 0; - char *e; - unsigned i, n = 0; - - p += strspn(p, WHITESPACE); - - if (*p == 0) { - if (!something) - return -EINVAL; - - break; - } - - errno = 0; - l = strtoll(p, &e, 10); - - if (errno > 0) - return -errno; - - if (l < 0) - return -ERANGE; - - if (*e == '.') { - char *b = e + 1; - - errno = 0; - z = strtoll(b, &e, 10); - if (errno > 0) - return -errno; - - if (z < 0) - return -ERANGE; - - if (e == b) - return -EINVAL; - - n = e - b; - - } else if (e == p) - return -EINVAL; - - e += strspn(e, WHITESPACE); - - for (i = 0; i < ELEMENTSOF(table); i++) - if (startswith(e, table[i].suffix)) { - nsec_t k = (nsec_t) z * table[i].nsec; - - for (; n > 0; n--) - k /= 10; - - r += (nsec_t) l * table[i].nsec + k; - p = e + strlen(table[i].suffix); - - something = true; - break; - } - - if (i >= ELEMENTSOF(table)) - return -EINVAL; - - } - - *nsec = r; - - return 0; -} - -bool ntp_synced(void) { - struct timex txc = {}; - - if (adjtimex(&txc) < 0) - return false; - - if (txc.status & STA_UNSYNC) - return false; - - return true; -} - -int get_timezones(char ***ret) { - _cleanup_fclose_ FILE *f = NULL; - _cleanup_strv_free_ char **zones = NULL; - size_t n_zones = 0, n_allocated = 0; - - assert(ret); - - zones = strv_new("UTC", NULL); - if (!zones) - return -ENOMEM; - - n_allocated = 2; - n_zones = 1; - - f = fopen("/usr/share/zoneinfo/zone.tab", "re"); - if (f) { - char l[LINE_MAX]; - - FOREACH_LINE(l, f, return -errno) { - char *p, *w; - size_t k; - - p = strstrip(l); - - if (isempty(p) || *p == '#') - continue; - - /* Skip over country code */ - p += strcspn(p, WHITESPACE); - p += strspn(p, WHITESPACE); - - /* Skip over coordinates */ - p += strcspn(p, WHITESPACE); - p += strspn(p, WHITESPACE); - - /* Found timezone name */ - k = strcspn(p, WHITESPACE); - if (k <= 0) - continue; - - w = strndup(p, k); - if (!w) - return -ENOMEM; - - if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) { - free(w); - return -ENOMEM; - } - - zones[n_zones++] = w; - zones[n_zones] = NULL; - } - - strv_sort(zones); - - } else if (errno != ENOENT) - return -errno; - - *ret = zones; - zones = NULL; - - return 0; -} - -bool timezone_is_valid(const char *name) { - bool slash = false; - const char *p, *t; - struct stat st; - - if (!name || *name == 0 || *name == '/') - return false; - - for (p = name; *p; p++) { - if (!(*p >= '0' && *p <= '9') && - !(*p >= 'a' && *p <= 'z') && - !(*p >= 'A' && *p <= 'Z') && - !(*p == '-' || *p == '_' || *p == '+' || *p == '/')) - return false; - - if (*p == '/') { - - if (slash) - return false; - - slash = true; - } else - slash = false; - } - - if (slash) - return false; - - t = strappenda("/usr/share/zoneinfo/", name); - if (stat(t, &st) < 0) - return false; - - if (!S_ISREG(st.st_mode)) - return false; - - return true; -} -#endif - -clockid_t clock_boottime_or_monotonic(void) { - static clockid_t clock = -1; - int fd; - - if (clock != -1) - return clock; - - fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC); - if (fd < 0) - clock = CLOCK_MONOTONIC; - else { - safe_close(fd); - clock = CLOCK_BOOTTIME; - } - - return clock; -} - diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/time-util.h b/src/dhcp-manager/systemd-dhcp/src/shared/time-util.h deleted file mode 100644 index 578a0c1c..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/time-util.h +++ /dev/null @@ -1,111 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include - -typedef uint64_t usec_t; -typedef uint64_t nsec_t; - -#include "nm-sd-adapt.h" - -#define NSEC_FMT "%" PRIu64 -#define USEC_FMT "%" PRIu64 - -#include "macro.h" - -typedef struct dual_timestamp { - usec_t realtime; - usec_t monotonic; -} dual_timestamp; - -#define USEC_INFINITY ((usec_t) -1) -#define NSEC_INFINITY ((nsec_t) -1) - -#define MSEC_PER_SEC 1000ULL -#define USEC_PER_SEC ((usec_t) 1000000ULL) -#define USEC_PER_MSEC ((usec_t) 1000ULL) -#define NSEC_PER_SEC ((nsec_t) 1000000000ULL) -#define NSEC_PER_MSEC ((nsec_t) 1000000ULL) -#define NSEC_PER_USEC ((nsec_t) 1000ULL) - -#define USEC_PER_MINUTE ((usec_t) (60ULL*USEC_PER_SEC)) -#define NSEC_PER_MINUTE ((nsec_t) (60ULL*NSEC_PER_SEC)) -#define USEC_PER_HOUR ((usec_t) (60ULL*USEC_PER_MINUTE)) -#define NSEC_PER_HOUR ((nsec_t) (60ULL*NSEC_PER_MINUTE)) -#define USEC_PER_DAY ((usec_t) (24ULL*USEC_PER_HOUR)) -#define NSEC_PER_DAY ((nsec_t) (24ULL*NSEC_PER_HOUR)) -#define USEC_PER_WEEK ((usec_t) (7ULL*USEC_PER_DAY)) -#define NSEC_PER_WEEK ((nsec_t) (7ULL*NSEC_PER_DAY)) -#define USEC_PER_MONTH ((usec_t) (2629800ULL*USEC_PER_SEC)) -#define NSEC_PER_MONTH ((nsec_t) (2629800ULL*NSEC_PER_SEC)) -#define USEC_PER_YEAR ((usec_t) (31557600ULL*USEC_PER_SEC)) -#define NSEC_PER_YEAR ((nsec_t) (31557600ULL*NSEC_PER_SEC)) - -#define FORMAT_TIMESTAMP_MAX ((4*4+1)+11+9+4+1) /* weekdays can be unicode */ -#define FORMAT_TIMESTAMP_WIDTH 28 /* when outputting, assume this width */ -#define FORMAT_TIMESTAMP_RELATIVE_MAX 256 -#define FORMAT_TIMESPAN_MAX 64 - -#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) - -#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0, 0 }) - -usec_t now(clockid_t clock); - -dual_timestamp* dual_timestamp_get(dual_timestamp *ts); -dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u); -dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u); - -static inline bool dual_timestamp_is_set(dual_timestamp *ts) { - return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) || - (ts->monotonic > 0 && ts->monotonic != USEC_INFINITY)); -} - -usec_t timespec_load(const struct timespec *ts) _pure_; -struct timespec *timespec_store(struct timespec *ts, usec_t u); - -usec_t timeval_load(const struct timeval *tv) _pure_; -struct timeval *timeval_store(struct timeval *tv, usec_t u); - -char *format_timestamp(char *buf, size_t l, usec_t t); -char *format_timestamp_utc(char *buf, size_t l, usec_t t); -char *format_timestamp_us(char *buf, size_t l, usec_t t); -char *format_timestamp_us_utc(char *buf, size_t l, usec_t t); -char *format_timestamp_relative(char *buf, size_t l, usec_t t); -char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy); - -void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t); -void dual_timestamp_deserialize(const char *value, dual_timestamp *t); - -int parse_timestamp(const char *t, usec_t *usec); - -int parse_sec(const char *t, usec_t *usec); -int parse_nsec(const char *t, nsec_t *nsec); - -bool ntp_synced(void); - -int get_timezones(char ***l); -bool timezone_is_valid(const char *name); - -clockid_t clock_boottime_or_monotonic(void); diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/unaligned.h b/src/dhcp-manager/systemd-dhcp/src/shared/unaligned.h deleted file mode 100644 index d6181dd9..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/unaligned.h +++ /dev/null @@ -1,66 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2014 Tom Gundersen - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include - -static inline uint16_t unaligned_read_be16(const void *_u) { - const uint8_t *u = _u; - - return (((uint16_t) u[0]) << 8) | - ((uint16_t) u[1]); -} - -static inline uint32_t unaligned_read_be32(const void *_u) { - const uint8_t *u = _u; - - return (((uint32_t) unaligned_read_be16(u)) << 16) | - ((uint32_t) unaligned_read_be16(u + 2)); -} - -static inline uint64_t unaligned_read_be64(const void *_u) { - const uint8_t *u = _u; - - return (((uint64_t) unaligned_read_be32(u)) << 32) | - ((uint64_t) unaligned_read_be32(u + 4)); -} - -static inline void unaligned_write_be16(void *_u, uint16_t a) { - uint8_t *u = _u; - - u[0] = (uint8_t) (a >> 8); - u[1] = (uint8_t) a; -} - -static inline void unaligned_write_be32(void *_u, uint32_t a) { - uint8_t *u = _u; - - unaligned_write_be16(u, (uint16_t) (a >> 16)); - unaligned_write_be16(u + 2, (uint16_t) a); -} - -static inline void unaligned_write_be64(void *_u, uint64_t a) { - uint8_t *u = _u; - - unaligned_write_be32(u, (uint32_t) (a >> 32)); - unaligned_write_be32(u + 4, (uint32_t) a); -} diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/utf8.c b/src/dhcp-manager/systemd-dhcp/src/shared/utf8.c deleted file mode 100644 index cfedbfcb..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/utf8.c +++ /dev/null @@ -1,314 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2008-2011 Kay Sievers - Copyright 2012 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -/* Parts of this file are based on the GLIB utf8 validation functions. The - * original license text follows. */ - -/* gutf8.c - Operations on UTF-8 strings. - * - * Copyright (C) 1999 Tom Tromey - * Copyright (C) 2000 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include "nm-sd-adapt.h" - -#include -#include -#include -#include -#include - -#include "utf8.h" -#include "util.h" - -static inline bool is_unicode_valid(uint32_t ch) { - - if (ch >= 0x110000) /* End of unicode space */ - return false; - if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ - return false; - if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ - return false; - if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ - return false; - - return true; -} - -static bool is_unicode_control(uint32_t ch) { - - /* - 0 to ' '-1 is the C0 range. - DEL=0x7F, and DEL+1 to 0x9F is C1 range. - '\t' is in C0 range, but more or less harmless and commonly used. - */ - - return (ch < ' ' && ch != '\t' && ch != '\n') || - (0x7F <= ch && ch <= 0x9F); -} - -/* count of characters used to encode one unicode char */ -static int utf8_encoded_expected_len(const char *str) { - unsigned char c; - - assert(str); - - c = (unsigned char) str[0]; - if (c < 0x80) - return 1; - if ((c & 0xe0) == 0xc0) - return 2; - if ((c & 0xf0) == 0xe0) - return 3; - if ((c & 0xf8) == 0xf0) - return 4; - if ((c & 0xfc) == 0xf8) - return 5; - if ((c & 0xfe) == 0xfc) - return 6; - - return 0; -} - -/* decode one unicode char */ -int utf8_encoded_to_unichar(const char *str) { - int unichar, len, i; - - assert(str); - - len = utf8_encoded_expected_len(str); - - switch (len) { - case 1: - return (int)str[0]; - case 2: - unichar = str[0] & 0x1f; - break; - case 3: - unichar = (int)str[0] & 0x0f; - break; - case 4: - unichar = (int)str[0] & 0x07; - break; - case 5: - unichar = (int)str[0] & 0x03; - break; - case 6: - unichar = (int)str[0] & 0x01; - break; - default: - return -EINVAL; - } - - for (i = 1; i < len; i++) { - if (((int)str[i] & 0xc0) != 0x80) - return -EINVAL; - unichar <<= 6; - unichar |= (int)str[i] & 0x3f; - } - - return unichar; -} - -bool utf8_is_printable_newline(const char* str, size_t length, bool newline) { - const uint8_t *p; - - assert(str); - - for (p = (const uint8_t*) str; length;) { - int encoded_len, val; - - encoded_len = utf8_encoded_valid_unichar((const char *) p); - if (encoded_len < 0 || - (size_t) encoded_len > length) - return false; - - val = utf8_encoded_to_unichar((const char*) p); - if (val < 0 || - is_unicode_control(val) || - (!newline && val == '\n')) - return false; - - length -= encoded_len; - p += encoded_len; - } - - return true; -} - -const char *utf8_is_valid(const char *str) { - const uint8_t *p; - - assert(str); - - for (p = (const uint8_t*) str; *p; ) { - int len; - - len = utf8_encoded_valid_unichar((const char *)p); - if (len < 0) - return NULL; - - p += len; - } - - return str; -} - -char *utf8_escape_invalid(const char *str) { - char *p, *s; - - assert(str); - - p = s = malloc(strlen(str) * 4 + 1); - if (!p) - return NULL; - - while (*str) { - int len; - - len = utf8_encoded_valid_unichar(str); - if (len > 0) { - s = mempcpy(s, str, len); - str += len; - } else { - s = mempcpy(s, UTF8_REPLACEMENT_CHARACTER, strlen(UTF8_REPLACEMENT_CHARACTER)); - str += 1; - } - } - - *s = '\0'; - - return p; -} - -char *ascii_is_valid(const char *str) { - const char *p; - - assert(str); - - for (p = str; *p; p++) - if ((unsigned char) *p >= 128) - return NULL; - - return (char*) str; -} - -char *utf16_to_utf8(const void *s, size_t length) { - char *r; - const uint8_t *f; - uint8_t *t; - - r = new(char, (length*3+1)/2 + 1); - if (!r) - return NULL; - - t = (uint8_t*) r; - - for (f = s; f < (const uint8_t*) s + length; f += 2) { - uint16_t c; - - c = (f[1] << 8) | f[0]; - - if (c == 0) { - *t = 0; - return r; - } else if (c < 0x80) { - *(t++) = (uint8_t) c; - } else if (c < 0x800) { - *(t++) = (uint8_t) (0xc0 | (c >> 6)); - *(t++) = (uint8_t) (0x80 | (c & 0x3f)); - } else { - *(t++) = (uint8_t) (0xe0 | (c >> 12)); - *(t++) = (uint8_t) (0x80 | ((c >> 6) & 0x3f)); - *(t++) = (uint8_t) (0x80 | (c & 0x3f)); - } - } - - *t = 0; - - return r; -} - -/* expected size used to encode one unicode char */ -static int utf8_unichar_to_encoded_len(int unichar) { - - if (unichar < 0x80) - return 1; - if (unichar < 0x800) - return 2; - if (unichar < 0x10000) - return 3; - if (unichar < 0x200000) - return 4; - if (unichar < 0x4000000) - return 5; - - return 6; -} - -/* validate one encoded unicode char and return its length */ -int utf8_encoded_valid_unichar(const char *str) { - int len, unichar, i; - - assert(str); - - len = utf8_encoded_expected_len(str); - if (len == 0) - return -EINVAL; - - /* ascii is valid */ - if (len == 1) - return 1; - - /* check if expected encoded chars are available */ - for (i = 0; i < len; i++) - if ((str[i] & 0x80) != 0x80) - return -EINVAL; - - unichar = utf8_encoded_to_unichar(str); - - /* check if encoded length matches encoded value */ - if (utf8_unichar_to_encoded_len(unichar) != len) - return -EINVAL; - - /* check if value has valid range */ - if (!is_unicode_valid(unichar)) - return -EINVAL; - - return len; -} diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/utf8.h b/src/dhcp-manager/systemd-dhcp/src/shared/utf8.h deleted file mode 100644 index c0879959..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/utf8.h +++ /dev/null @@ -1,42 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2012 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include - -#include "macro.h" - -#define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd" - -const char *utf8_is_valid(const char *s) _pure_; -char *ascii_is_valid(const char *s) _pure_; -char *utf8_escape_invalid(const char *s); - -bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pure_; -_pure_ static inline bool utf8_is_printable(const char* str, size_t length) { - return utf8_is_printable_newline(str, length, true); -} - -char *utf16_to_utf8(const void *s, size_t length); - -int utf8_encoded_valid_unichar(const char *str); -int utf8_encoded_to_unichar(const char *str); diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/util.c b/src/dhcp-manager/systemd-dhcp/src/shared/util.c deleted file mode 100644 index 05d4eb75..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/util.c +++ /dev/null @@ -1,7350 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "config.h" - -#include "nm-sd-adapt.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#undef basename - -#ifdef HAVE_SYS_AUXV_H -#include -#endif - -#include "macro.h" -#include "util.h" -#if 0 /* NM_IGNORED */ -#include "ioprio.h" -#include "missing.h" -#include "log.h" -#include "strv.h" -#include "label.h" -#include "mkdir.h" -#include "path-util.h" -#include "exit-status.h" -#include "hashmap.h" -#include "env-util.h" -#include "fileio.h" -#include "device-nodes.h" -#include "utf8.h" -#include "gunicode.h" -#include "virt.h" -#include "def.h" -#endif - -#if 0 /* NM_IGNORED */ -int saved_argc = 0; -char **saved_argv = NULL; - -static volatile unsigned cached_columns = 0; -static volatile unsigned cached_lines = 0; - -size_t page_size(void) { - static thread_local size_t pgsz = 0; - long r; - - if (_likely_(pgsz > 0)) - return pgsz; - - r = sysconf(_SC_PAGESIZE); - assert(r > 0); - - pgsz = (size_t) r; - return pgsz; -} -#endif - -bool streq_ptr(const char *a, const char *b) { - - /* Like streq(), but tries to make sense of NULL pointers */ - - if (a && b) - return streq(a, b); - - if (!a && !b) - return true; - - return false; -} - -char* endswith(const char *s, const char *postfix) { - size_t sl, pl; - - assert(s); - assert(postfix); - - sl = strlen(s); - pl = strlen(postfix); - - if (pl == 0) - return (char*) s + sl; - - if (sl < pl) - return NULL; - - if (memcmp(s + sl - pl, postfix, pl) != 0) - return NULL; - - return (char*) s + sl - pl; -} - -char* first_word(const char *s, const char *word) { - size_t sl, wl; - const char *p; - - assert(s); - assert(word); - - /* Checks if the string starts with the specified word, either - * followed by NUL or by whitespace. Returns a pointer to the - * NUL or the first character after the whitespace. */ - - sl = strlen(s); - wl = strlen(word); - - if (sl < wl) - return NULL; - - if (wl == 0) - return (char*) s; - - if (memcmp(s, word, wl) != 0) - return NULL; - - p = s + wl; - if (*p == 0) - return (char*) p; - - if (!strchr(WHITESPACE, *p)) - return NULL; - - p += strspn(p, WHITESPACE); - return (char*) p; -} - -int close_nointr(int fd) { - assert(fd >= 0); - - if (close(fd) >= 0) - return 0; - - /* - * Just ignore EINTR; a retry loop is the wrong thing to do on - * Linux. - * - * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html - * https://bugzilla.gnome.org/show_bug.cgi?id=682819 - * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR - * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain - */ - if (errno == EINTR) - return 0; - - return -errno; -} - -int safe_close(int fd) { - - /* - * Like close_nointr() but cannot fail. Guarantees errno is - * unchanged. Is a NOP with negative fds passed, and returns - * -1, so that it can be used in this syntax: - * - * fd = safe_close(fd); - */ - - if (fd >= 0) { - PROTECT_ERRNO; - - /* The kernel might return pretty much any error code - * via close(), but the fd will be closed anyway. The - * only condition we want to check for here is whether - * the fd was invalid at all... */ - - assert_se(close_nointr(fd) != -EBADF); - } - - return -1; -} - -#if 0 /* NM_IGNORED */ -void close_many(const int fds[], unsigned n_fd) { - unsigned i; - - assert(fds || n_fd <= 0); - - for (i = 0; i < n_fd; i++) - safe_close(fds[i]); -} - -int unlink_noerrno(const char *path) { - PROTECT_ERRNO; - int r; - - r = unlink(path); - if (r < 0) - return -errno; - - return 0; -} - -int parse_boolean(const char *v) { - assert(v); - - if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on")) - return 1; - else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off")) - return 0; - - return -EINVAL; -} - -int parse_pid(const char *s, pid_t* ret_pid) { - unsigned long ul = 0; - pid_t pid; - int r; - - assert(s); - assert(ret_pid); - - r = safe_atolu(s, &ul); - if (r < 0) - return r; - - pid = (pid_t) ul; - - if ((unsigned long) pid != ul) - return -ERANGE; - - if (pid <= 0) - return -ERANGE; - - *ret_pid = pid; - return 0; -} - -int parse_uid(const char *s, uid_t* ret_uid) { - unsigned long ul = 0; - uid_t uid; - int r; - - assert(s); - assert(ret_uid); - - r = safe_atolu(s, &ul); - if (r < 0) - return r; - - uid = (uid_t) ul; - - if ((unsigned long) uid != ul) - return -ERANGE; - - /* Some libc APIs use (uid_t) -1 as special placeholder */ - if (uid == (uid_t) 0xFFFFFFFF) - return -ENXIO; - - /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */ - if (uid == (uid_t) 0xFFFF) - return -ENXIO; - - *ret_uid = uid; - return 0; -} -#endif - -int safe_atou(const char *s, unsigned *ret_u) { - char *x = NULL; - unsigned long l; - - assert(s); - assert(ret_u); - - errno = 0; - l = strtoul(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((unsigned long) (unsigned) l != l) - return -ERANGE; - - *ret_u = (unsigned) l; - return 0; -} - -#if 0 /* NM_IGNORED */ -int safe_atoi(const char *s, int *ret_i) { - char *x = NULL; - long l; - - assert(s); - assert(ret_i); - - errno = 0; - l = strtol(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((long) (int) l != l) - return -ERANGE; - - *ret_i = (int) l; - return 0; -} - -int safe_atou8(const char *s, uint8_t *ret) { - char *x = NULL; - unsigned long l; - - assert(s); - assert(ret); - - errno = 0; - l = strtoul(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((unsigned long) (uint8_t) l != l) - return -ERANGE; - - *ret = (uint8_t) l; - return 0; -} - -int safe_atou16(const char *s, uint16_t *ret) { - char *x = NULL; - unsigned long l; - - assert(s); - assert(ret); - - errno = 0; - l = strtoul(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((unsigned long) (uint16_t) l != l) - return -ERANGE; - - *ret = (uint16_t) l; - return 0; -} - -int safe_atoi16(const char *s, int16_t *ret) { - char *x = NULL; - long l; - - assert(s); - assert(ret); - - errno = 0; - l = strtol(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno > 0 ? -errno : -EINVAL; - - if ((long) (int16_t) l != l) - return -ERANGE; - - *ret = (int16_t) l; - return 0; -} - -int safe_atollu(const char *s, long long unsigned *ret_llu) { - char *x = NULL; - unsigned long long l; - - assert(s); - assert(ret_llu); - - errno = 0; - l = strtoull(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; - - *ret_llu = l; - return 0; -} - -int safe_atolli(const char *s, long long int *ret_lli) { - char *x = NULL; - long long l; - - assert(s); - assert(ret_lli); - - errno = 0; - l = strtoll(s, &x, 0); - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; - - *ret_lli = l; - return 0; -} - -int safe_atod(const char *s, double *ret_d) { - char *x = NULL; - double d = 0; - - assert(s); - assert(ret_d); - - RUN_WITH_LOCALE(LC_NUMERIC_MASK, "C") { - errno = 0; - d = strtod(s, &x); - } - - if (!x || x == s || *x || errno) - return errno ? -errno : -EINVAL; - - *ret_d = (double) d; - return 0; -} -#endif - -static size_t strcspn_escaped(const char *s, const char *reject) { - bool escaped = false; - size_t n; - - for (n=0; s[n]; n++) { - if (escaped) - escaped = false; - else if (s[n] == '\\') - escaped = true; - else if (strchr(reject, s[n])) - break; - } - /* if s ends in \, return index of previous char */ - return n - escaped; -} - -/* Split a string into words. */ -const char* split(const char **state, size_t *l, const char *separator, bool quoted) { - const char *current; - - current = *state; - - if (!*current) { - assert(**state == '\0'); - return NULL; - } - - current += strspn(current, separator); - if (!*current) { - *state = current; - return NULL; - } - - if (quoted && strchr("\'\"", *current)) { - char quotechars[2] = {*current, '\0'}; - - *l = strcspn_escaped(current + 1, quotechars); - if (current[*l + 1] == '\0' || - (current[*l + 2] && !strchr(separator, current[*l + 2]))) { - /* right quote missing or garbage at the end*/ - *state = current; - return NULL; - } - assert(current[*l + 1] == quotechars[0]); - *state = current++ + *l + 2; - } else if (quoted) { - *l = strcspn_escaped(current, separator); - *state = current + *l; - } else { - *l = strcspn(current, separator); - *state = current + *l; - } - - return current; -} - -#if 0 /* NM_IGNORED */ -int get_parent_of_pid(pid_t pid, pid_t *_ppid) { - int r; - _cleanup_free_ char *line = NULL; - long unsigned ppid; - const char *p; - - assert(pid >= 0); - assert(_ppid); - - if (pid == 0) { - *_ppid = getppid(); - return 0; - } - - p = procfs_file_alloca(pid, "stat"); - r = read_one_line_file(p, &line); - if (r < 0) - return r; - - /* Let's skip the pid and comm fields. The latter is enclosed - * in () but does not escape any () in its value, so let's - * skip over it manually */ - - p = strrchr(line, ')'); - if (!p) - return -EIO; - - p++; - - if (sscanf(p, " " - "%*c " /* state */ - "%lu ", /* ppid */ - &ppid) != 1) - return -EIO; - - if ((long unsigned) (pid_t) ppid != ppid) - return -ERANGE; - - *_ppid = (pid_t) ppid; - - return 0; -} - -int get_starttime_of_pid(pid_t pid, unsigned long long *st) { - int r; - _cleanup_free_ char *line = NULL; - const char *p; - - assert(pid >= 0); - assert(st); - - p = procfs_file_alloca(pid, "stat"); - r = read_one_line_file(p, &line); - if (r < 0) - return r; - - /* Let's skip the pid and comm fields. The latter is enclosed - * in () but does not escape any () in its value, so let's - * skip over it manually */ - - p = strrchr(line, ')'); - if (!p) - return -EIO; - - p++; - - if (sscanf(p, " " - "%*c " /* state */ - "%*d " /* ppid */ - "%*d " /* pgrp */ - "%*d " /* session */ - "%*d " /* tty_nr */ - "%*d " /* tpgid */ - "%*u " /* flags */ - "%*u " /* minflt */ - "%*u " /* cminflt */ - "%*u " /* majflt */ - "%*u " /* cmajflt */ - "%*u " /* utime */ - "%*u " /* stime */ - "%*d " /* cutime */ - "%*d " /* cstime */ - "%*d " /* priority */ - "%*d " /* nice */ - "%*d " /* num_threads */ - "%*d " /* itrealvalue */ - "%llu " /* starttime */, - st) != 1) - return -EIO; - - return 0; -} -#endif - -int fchmod_umask(int fd, mode_t m) { - mode_t u; - int r; - - u = umask(0777); - r = fchmod(fd, m & (~u)) < 0 ? -errno : 0; - umask(u); - - return r; -} - -char *truncate_nl(char *s) { - assert(s); - - s[strcspn(s, NEWLINE)] = 0; - return s; -} - -#if 0 /* NM_IGNORED */ -int get_process_state(pid_t pid) { - const char *p; - char state; - int r; - _cleanup_free_ char *line = NULL; - - assert(pid >= 0); - - p = procfs_file_alloca(pid, "stat"); - r = read_one_line_file(p, &line); - if (r < 0) - return r; - - p = strrchr(line, ')'); - if (!p) - return -EIO; - - p++; - - if (sscanf(p, " %c", &state) != 1) - return -EIO; - - return (unsigned char) state; -} - -int get_process_comm(pid_t pid, char **name) { - const char *p; - int r; - - assert(name); - assert(pid >= 0); - - p = procfs_file_alloca(pid, "comm"); - - r = read_one_line_file(p, name); - if (r == -ENOENT) - return -ESRCH; - - return r; -} - -int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) { - _cleanup_fclose_ FILE *f = NULL; - char *r = NULL, *k; - const char *p; - int c; - - assert(line); - assert(pid >= 0); - - p = procfs_file_alloca(pid, "cmdline"); - - f = fopen(p, "re"); - if (!f) - return -errno; - - if (max_length == 0) { - size_t len = 0, allocated = 0; - - while ((c = getc(f)) != EOF) { - - if (!GREEDY_REALLOC(r, allocated, len+2)) { - free(r); - return -ENOMEM; - } - - r[len++] = isprint(c) ? c : ' '; - } - - if (len > 0) - r[len-1] = 0; - - } else { - bool space = false; - size_t left; - - r = new(char, max_length); - if (!r) - return -ENOMEM; - - k = r; - left = max_length; - while ((c = getc(f)) != EOF) { - - if (isprint(c)) { - if (space) { - if (left <= 4) - break; - - *(k++) = ' '; - left--; - space = false; - } - - if (left <= 4) - break; - - *(k++) = (char) c; - left--; - } else - space = true; - } - - if (left <= 4) { - size_t n = MIN(left-1, 3U); - memcpy(k, "...", n); - k[n] = 0; - } else - *k = 0; - } - - /* Kernel threads have no argv[] */ - if (isempty(r)) { - _cleanup_free_ char *t = NULL; - int h; - - free(r); - - if (!comm_fallback) - return -ENOENT; - - h = get_process_comm(pid, &t); - if (h < 0) - return h; - - r = strjoin("[", t, "]", NULL); - if (!r) - return -ENOMEM; - } - - *line = r; - return 0; -} - -int is_kernel_thread(pid_t pid) { - const char *p; - size_t count; - char c; - bool eof; - FILE *f; - - if (pid == 0) - return 0; - - assert(pid > 0); - - p = procfs_file_alloca(pid, "cmdline"); - f = fopen(p, "re"); - if (!f) - return -errno; - - count = fread(&c, 1, 1, f); - eof = feof(f); - fclose(f); - - /* Kernel threads have an empty cmdline */ - - if (count <= 0) - return eof ? 1 : -errno; - - return 0; -} - -int get_process_capeff(pid_t pid, char **capeff) { - const char *p; - - assert(capeff); - assert(pid >= 0); - - p = procfs_file_alloca(pid, "status"); - - return get_status_field(p, "\nCapEff:", capeff); -} - -int get_process_exe(pid_t pid, char **name) { - const char *p; - char *d; - int r; - - assert(pid >= 0); - assert(name); - - p = procfs_file_alloca(pid, "exe"); - - r = readlink_malloc(p, name); - if (r < 0) - return r == -ENOENT ? -ESRCH : r; - - d = endswith(*name, " (deleted)"); - if (d) - *d = '\0'; - - return 0; -} - -static int get_process_id(pid_t pid, const char *field, uid_t *uid) { - _cleanup_fclose_ FILE *f = NULL; - char line[LINE_MAX]; - const char *p; - - assert(field); - assert(uid); - - if (pid == 0) - return getuid(); - - p = procfs_file_alloca(pid, "status"); - f = fopen(p, "re"); - if (!f) - return -errno; - - FOREACH_LINE(line, f, return -errno) { - char *l; - - l = strstrip(line); - - if (startswith(l, field)) { - l += strlen(field); - l += strspn(l, WHITESPACE); - - l[strcspn(l, WHITESPACE)] = 0; - - return parse_uid(l, uid); - } - } - - return -EIO; -} - -int get_process_uid(pid_t pid, uid_t *uid) { - return get_process_id(pid, "Uid:", uid); -} - -int get_process_gid(pid_t pid, gid_t *gid) { - assert_cc(sizeof(uid_t) == sizeof(gid_t)); - return get_process_id(pid, "Gid:", gid); -} -#endif - -char *strnappend(const char *s, const char *suffix, size_t b) { - size_t a; - char *r; - - if (!s && !suffix) - return strdup(""); - - if (!s) - return strndup(suffix, b); - - if (!suffix) - return strdup(s); - - assert(s); - assert(suffix); - - a = strlen(s); - if (b > ((size_t) -1) - a) - return NULL; - - r = new(char, a+b+1); - if (!r) - return NULL; - - memcpy(r, s, a); - memcpy(r+a, suffix, b); - r[a+b] = 0; - - return r; -} - -char *strappend(const char *s, const char *suffix) { - return strnappend(s, suffix, suffix ? strlen(suffix) : 0); -} - -#if 0 /* NM_IGNORED */ -int readlinkat_malloc(int fd, const char *p, char **ret) { - size_t l = 100; - int r; - - assert(p); - assert(ret); - - for (;;) { - char *c; - ssize_t n; - - c = new(char, l); - if (!c) - return -ENOMEM; - - n = readlinkat(fd, p, c, l-1); - if (n < 0) { - r = -errno; - free(c); - return r; - } - - if ((size_t) n < l-1) { - c[n] = 0; - *ret = c; - return 0; - } - - free(c); - l *= 2; - } -} - -int readlink_malloc(const char *p, char **ret) { - return readlinkat_malloc(AT_FDCWD, p, ret); -} - -int readlink_value(const char *p, char **ret) { - _cleanup_free_ char *link = NULL; - char *value; - int r; - - r = readlink_malloc(p, &link); - if (r < 0) - return r; - - value = basename(link); - if (!value) - return -ENOENT; - - value = strdup(value); - if (!value) - return -ENOMEM; - - *ret = value; - - return 0; -} - -int readlink_and_make_absolute(const char *p, char **r) { - _cleanup_free_ char *target = NULL; - char *k; - int j; - - assert(p); - assert(r); - - j = readlink_malloc(p, &target); - if (j < 0) - return j; - - k = file_in_same_dir(p, target); - if (!k) - return -ENOMEM; - - *r = k; - return 0; -} - -int readlink_and_canonicalize(const char *p, char **r) { - char *t, *s; - int j; - - assert(p); - assert(r); - - j = readlink_and_make_absolute(p, &t); - if (j < 0) - return j; - - s = canonicalize_file_name(t); - if (s) { - free(t); - *r = s; - } else - *r = t; - - path_kill_slashes(*r); - - return 0; -} - -int reset_all_signal_handlers(void) { - int sig, r = 0; - - for (sig = 1; sig < _NSIG; sig++) { - struct sigaction sa = { - .sa_handler = SIG_DFL, - .sa_flags = SA_RESTART, - }; - - /* These two cannot be caught... */ - if (sig == SIGKILL || sig == SIGSTOP) - continue; - - /* On Linux the first two RT signals are reserved by - * glibc, and sigaction() will return EINVAL for them. */ - if ((sigaction(sig, &sa, NULL) < 0)) - if (errno != EINVAL && r == 0) - r = -errno; - } - - return r; -} - -int reset_signal_mask(void) { - sigset_t ss; - - if (sigemptyset(&ss) < 0) - return -errno; - - if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0) - return -errno; - - return 0; -} -#endif - -char *strstrip(char *s) { - char *e; - - /* Drops trailing whitespace. Modifies the string in - * place. Returns pointer to first non-space character */ - - s += strspn(s, WHITESPACE); - - for (e = strchr(s, 0); e > s; e --) - if (!strchr(WHITESPACE, e[-1])) - break; - - *e = 0; - - return s; -} - -#if 0 /* NM_IGNORED */ -char *delete_chars(char *s, const char *bad) { - char *f, *t; - - /* Drops all whitespace, regardless where in the string */ - - for (f = s, t = s; *f; f++) { - if (strchr(bad, *f)) - continue; - - *(t++) = *f; - } - - *t = 0; - - return s; -} - -char *file_in_same_dir(const char *path, const char *filename) { - char *e, *r; - size_t k; - - assert(path); - assert(filename); - - /* This removes the last component of path and appends - * filename, unless the latter is absolute anyway or the - * former isn't */ - - if (path_is_absolute(filename)) - return strdup(filename); - - if (!(e = strrchr(path, '/'))) - return strdup(filename); - - k = strlen(filename); - if (!(r = new(char, e-path+1+k+1))) - return NULL; - - memcpy(r, path, e-path+1); - memcpy(r+(e-path)+1, filename, k+1); - - return r; -} - -int rmdir_parents(const char *path, const char *stop) { - size_t l; - int r = 0; - - assert(path); - assert(stop); - - l = strlen(path); - - /* Skip trailing slashes */ - while (l > 0 && path[l-1] == '/') - l--; - - while (l > 0) { - char *t; - - /* Skip last component */ - while (l > 0 && path[l-1] != '/') - l--; - - /* Skip trailing slashes */ - while (l > 0 && path[l-1] == '/') - l--; - - if (l <= 0) - break; - - if (!(t = strndup(path, l))) - return -ENOMEM; - - if (path_startswith(stop, t)) { - free(t); - return 0; - } - - r = rmdir(t); - free(t); - - if (r < 0) - if (errno != ENOENT) - return -errno; - } - - return 0; -} -#endif - -char hexchar(int x) { - static const char table[16] = "0123456789abcdef"; - - return table[x & 15]; -} - -int unhexchar(char c) { - - if (c >= '0' && c <= '9') - return c - '0'; - - if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - - if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - - return -EINVAL; -} - -char *hexmem(const void *p, size_t l) { - char *r, *z; - const uint8_t *x; - - z = r = malloc(l * 2 + 1); - if (!r) - return NULL; - - for (x = p; x < (const uint8_t*) p + l; x++) { - *(z++) = hexchar(*x >> 4); - *(z++) = hexchar(*x & 15); - } - - *z = 0; - return r; -} - -void *unhexmem(const char *p, size_t l) { - uint8_t *r, *z; - const char *x; - - assert(p); - - z = r = malloc((l + 1) / 2 + 1); - if (!r) - return NULL; - - for (x = p; x < p + l; x += 2) { - int a, b; - - a = unhexchar(x[0]); - if (x+1 < p + l) - b = unhexchar(x[1]); - else - b = 0; - - *(z++) = (uint8_t) a << 4 | (uint8_t) b; - } - - *z = 0; - return r; -} - -char octchar(int x) { - return '0' + (x & 7); -} - -int unoctchar(char c) { - - if (c >= '0' && c <= '7') - return c - '0'; - - return -EINVAL; -} - -char decchar(int x) { - return '0' + (x % 10); -} - -int undecchar(char c) { - - if (c >= '0' && c <= '9') - return c - '0'; - - return -EINVAL; -} - -char *cescape(const char *s) { - char *r, *t; - const char *f; - - assert(s); - - /* Does C style string escaping. */ - - r = new(char, strlen(s)*4 + 1); - if (!r) - return NULL; - - for (f = s, t = r; *f; f++) - - switch (*f) { - - case '\a': - *(t++) = '\\'; - *(t++) = 'a'; - break; - case '\b': - *(t++) = '\\'; - *(t++) = 'b'; - break; - case '\f': - *(t++) = '\\'; - *(t++) = 'f'; - break; - case '\n': - *(t++) = '\\'; - *(t++) = 'n'; - break; - case '\r': - *(t++) = '\\'; - *(t++) = 'r'; - break; - case '\t': - *(t++) = '\\'; - *(t++) = 't'; - break; - case '\v': - *(t++) = '\\'; - *(t++) = 'v'; - break; - case '\\': - *(t++) = '\\'; - *(t++) = '\\'; - break; - case '"': - *(t++) = '\\'; - *(t++) = '"'; - break; - case '\'': - *(t++) = '\\'; - *(t++) = '\''; - break; - - default: - /* For special chars we prefer octal over - * hexadecimal encoding, simply because glib's - * g_strescape() does the same */ - if ((*f < ' ') || (*f >= 127)) { - *(t++) = '\\'; - *(t++) = octchar((unsigned char) *f >> 6); - *(t++) = octchar((unsigned char) *f >> 3); - *(t++) = octchar((unsigned char) *f); - } else - *(t++) = *f; - break; - } - - *t = 0; - - return r; -} - -char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix) { - char *r, *t; - const char *f; - size_t pl; - - assert(s); - - /* Undoes C style string escaping, and optionally prefixes it. */ - - pl = prefix ? strlen(prefix) : 0; - - r = new(char, pl+length+1); - if (!r) - return NULL; - - if (prefix) - memcpy(r, prefix, pl); - - for (f = s, t = r + pl; f < s + length; f++) { - - if (*f != '\\') { - *(t++) = *f; - continue; - } - - f++; - - switch (*f) { - - case 'a': - *(t++) = '\a'; - break; - case 'b': - *(t++) = '\b'; - break; - case 'f': - *(t++) = '\f'; - break; - case 'n': - *(t++) = '\n'; - break; - case 'r': - *(t++) = '\r'; - break; - case 't': - *(t++) = '\t'; - break; - case 'v': - *(t++) = '\v'; - break; - case '\\': - *(t++) = '\\'; - break; - case '"': - *(t++) = '"'; - break; - case '\'': - *(t++) = '\''; - break; - - case 's': - /* This is an extension of the XDG syntax files */ - *(t++) = ' '; - break; - - case 'x': { - /* hexadecimal encoding */ - int a, b; - - a = unhexchar(f[1]); - b = unhexchar(f[2]); - - if (a < 0 || b < 0 || (a == 0 && b == 0)) { - /* Invalid escape code, let's take it literal then */ - *(t++) = '\\'; - *(t++) = 'x'; - } else { - *(t++) = (char) ((a << 4) | b); - f += 2; - } - - break; - } - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': { - /* octal encoding */ - int a, b, c; - - a = unoctchar(f[0]); - b = unoctchar(f[1]); - c = unoctchar(f[2]); - - if (a < 0 || b < 0 || c < 0 || (a == 0 && b == 0 && c == 0)) { - /* Invalid escape code, let's take it literal then */ - *(t++) = '\\'; - *(t++) = f[0]; - } else { - *(t++) = (char) ((a << 6) | (b << 3) | c); - f += 2; - } - - break; - } - - case 0: - /* premature end of string.*/ - *(t++) = '\\'; - goto finish; - - default: - /* Invalid escape code, let's take it literal then */ - *(t++) = '\\'; - *(t++) = *f; - break; - } - } - -finish: - *t = 0; - return r; -} - -char *cunescape_length(const char *s, size_t length) { - return cunescape_length_with_prefix(s, length, NULL); -} - -#if 0 /* NM_IGNORED */ -char *cunescape(const char *s) { - assert(s); - - return cunescape_length(s, strlen(s)); -} - -char *xescape(const char *s, const char *bad) { - char *r, *t; - const char *f; - - /* Escapes all chars in bad, in addition to \ and all special - * chars, in \xFF style escaping. May be reversed with - * cunescape. */ - - r = new(char, strlen(s) * 4 + 1); - if (!r) - return NULL; - - for (f = s, t = r; *f; f++) { - - if ((*f < ' ') || (*f >= 127) || - (*f == '\\') || strchr(bad, *f)) { - *(t++) = '\\'; - *(t++) = 'x'; - *(t++) = hexchar(*f >> 4); - *(t++) = hexchar(*f); - } else - *(t++) = *f; - } - - *t = 0; - - return r; -} - -char *ascii_strlower(char *t) { - char *p; - - assert(t); - - for (p = t; *p; p++) - if (*p >= 'A' && *p <= 'Z') - *p = *p - 'A' + 'a'; - - return t; -} - -_pure_ static bool ignore_file_allow_backup(const char *filename) { - assert(filename); - - return - filename[0] == '.' || - streq(filename, "lost+found") || - streq(filename, "aquota.user") || - streq(filename, "aquota.group") || - endswith(filename, ".rpmnew") || - endswith(filename, ".rpmsave") || - endswith(filename, ".rpmorig") || - endswith(filename, ".dpkg-old") || - endswith(filename, ".dpkg-new") || - endswith(filename, ".dpkg-tmp") || - endswith(filename, ".swp"); -} - -bool ignore_file(const char *filename) { - assert(filename); - - if (endswith(filename, "~")) - return true; - - return ignore_file_allow_backup(filename); -} - -int fd_nonblock(int fd, bool nonblock) { - int flags, nflags; - - assert(fd >= 0); - - flags = fcntl(fd, F_GETFL, 0); - if (flags < 0) - return -errno; - - if (nonblock) - nflags = flags | O_NONBLOCK; - else - nflags = flags & ~O_NONBLOCK; - - if (nflags == flags) - return 0; - - if (fcntl(fd, F_SETFL, nflags) < 0) - return -errno; - - return 0; -} - -int fd_cloexec(int fd, bool cloexec) { - int flags, nflags; - - assert(fd >= 0); - - flags = fcntl(fd, F_GETFD, 0); - if (flags < 0) - return -errno; - - if (cloexec) - nflags = flags | FD_CLOEXEC; - else - nflags = flags & ~FD_CLOEXEC; - - if (nflags == flags) - return 0; - - if (fcntl(fd, F_SETFD, nflags) < 0) - return -errno; - - return 0; -} - -_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { - unsigned i; - - assert(n_fdset == 0 || fdset); - - for (i = 0; i < n_fdset; i++) - if (fdset[i] == fd) - return true; - - return false; -} - -int close_all_fds(const int except[], unsigned n_except) { - _cleanup_closedir_ DIR *d = NULL; - struct dirent *de; - int r = 0; - - assert(n_except == 0 || except); - - d = opendir("/proc/self/fd"); - if (!d) { - int fd; - struct rlimit rl; - - /* When /proc isn't available (for example in chroots) - * the fallback is brute forcing through the fd - * table */ - - assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0); - for (fd = 3; fd < (int) rl.rlim_max; fd ++) { - - if (fd_in_set(fd, except, n_except)) - continue; - - if (close_nointr(fd) < 0) - if (errno != EBADF && r == 0) - r = -errno; - } - - return r; - } - - while ((de = readdir(d))) { - int fd = -1; - - if (ignore_file(de->d_name)) - continue; - - if (safe_atoi(de->d_name, &fd) < 0) - /* Let's better ignore this, just in case */ - continue; - - if (fd < 3) - continue; - - if (fd == dirfd(d)) - continue; - - if (fd_in_set(fd, except, n_except)) - continue; - - if (close_nointr(fd) < 0) { - /* Valgrind has its own FD and doesn't want to have it closed */ - if (errno != EBADF && r == 0) - r = -errno; - } - } - - return r; -} -#endif - -bool chars_intersect(const char *a, const char *b) { - const char *p; - - /* Returns true if any of the chars in a are in b. */ - for (p = a; *p; p++) - if (strchr(b, *p)) - return true; - - return false; -} - -#if 0 /* NM_IGNORED */ -bool fstype_is_network(const char *fstype) { - static const char table[] = - "cifs\0" - "smbfs\0" - "sshfs\0" - "ncpfs\0" - "ncp\0" - "nfs\0" - "nfs4\0" - "gfs\0" - "gfs2\0" - "glusterfs\0"; - - const char *x; - - x = startswith(fstype, "fuse."); - if (x) - fstype = x; - - return nulstr_contains(table, fstype); -} - -int chvt(int vt) { - _cleanup_close_ int fd = -1; - - fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return -errno; - - if (vt < 0) { - int tiocl[2] = { - TIOCL_GETKMSGREDIRECT, - 0 - }; - - if (ioctl(fd, TIOCLINUX, tiocl) < 0) - return -errno; - - vt = tiocl[0] <= 0 ? 1 : tiocl[0]; - } - - if (ioctl(fd, VT_ACTIVATE, vt) < 0) - return -errno; - - return 0; -} - -int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) { - struct termios old_termios, new_termios; - char c, line[LINE_MAX]; - - assert(f); - assert(ret); - - if (tcgetattr(fileno(f), &old_termios) >= 0) { - new_termios = old_termios; - - new_termios.c_lflag &= ~ICANON; - new_termios.c_cc[VMIN] = 1; - new_termios.c_cc[VTIME] = 0; - - if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) { - size_t k; - - if (t != USEC_INFINITY) { - if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) { - tcsetattr(fileno(f), TCSADRAIN, &old_termios); - return -ETIMEDOUT; - } - } - - k = fread(&c, 1, 1, f); - - tcsetattr(fileno(f), TCSADRAIN, &old_termios); - - if (k <= 0) - return -EIO; - - if (need_nl) - *need_nl = c != '\n'; - - *ret = c; - return 0; - } - } - - if (t != USEC_INFINITY) { - if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) - return -ETIMEDOUT; - } - - errno = 0; - if (!fgets(line, sizeof(line), f)) - return errno ? -errno : -EIO; - - truncate_nl(line); - - if (strlen(line) != 1) - return -EBADMSG; - - if (need_nl) - *need_nl = false; - - *ret = line[0]; - return 0; -} - -int ask_char(char *ret, const char *replies, const char *text, ...) { - int r; - - assert(ret); - assert(replies); - assert(text); - - for (;;) { - va_list ap; - char c; - bool need_nl = true; - - if (on_tty()) - fputs(ANSI_HIGHLIGHT_ON, stdout); - - va_start(ap, text); - vprintf(text, ap); - va_end(ap); - - if (on_tty()) - fputs(ANSI_HIGHLIGHT_OFF, stdout); - - fflush(stdout); - - r = read_one_char(stdin, &c, USEC_INFINITY, &need_nl); - if (r < 0) { - - if (r == -EBADMSG) { - puts("Bad input, please try again."); - continue; - } - - putchar('\n'); - return r; - } - - if (need_nl) - putchar('\n'); - - if (strchr(replies, c)) { - *ret = c; - return 0; - } - - puts("Read unexpected character, please try again."); - } -} - -int ask_string(char **ret, const char *text, ...) { - assert(ret); - assert(text); - - for (;;) { - char line[LINE_MAX]; - va_list ap; - - if (on_tty()) - fputs(ANSI_HIGHLIGHT_ON, stdout); - - va_start(ap, text); - vprintf(text, ap); - va_end(ap); - - if (on_tty()) - fputs(ANSI_HIGHLIGHT_OFF, stdout); - - fflush(stdout); - - errno = 0; - if (!fgets(line, sizeof(line), stdin)) - return errno ? -errno : -EIO; - - if (!endswith(line, "\n")) - putchar('\n'); - else { - char *s; - - if (isempty(line)) - continue; - - truncate_nl(line); - s = strdup(line); - if (!s) - return -ENOMEM; - - *ret = s; - return 0; - } - } -} - -int reset_terminal_fd(int fd, bool switch_to_text) { - struct termios termios; - int r = 0; - - /* Set terminal to some sane defaults */ - - assert(fd >= 0); - - /* We leave locked terminal attributes untouched, so that - * Plymouth may set whatever it wants to set, and we don't - * interfere with that. */ - - /* Disable exclusive mode, just in case */ - ioctl(fd, TIOCNXCL); - - /* Switch to text mode */ - if (switch_to_text) - ioctl(fd, KDSETMODE, KD_TEXT); - - /* Enable console unicode mode */ - ioctl(fd, KDSKBMODE, K_UNICODE); - - if (tcgetattr(fd, &termios) < 0) { - r = -errno; - goto finish; - } - - /* We only reset the stuff that matters to the software. How - * hardware is set up we don't touch assuming that somebody - * else will do that for us */ - - termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC); - termios.c_iflag |= ICRNL | IMAXBEL | IUTF8; - termios.c_oflag |= ONLCR; - termios.c_cflag |= CREAD; - termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE; - - termios.c_cc[VINTR] = 03; /* ^C */ - termios.c_cc[VQUIT] = 034; /* ^\ */ - termios.c_cc[VERASE] = 0177; - termios.c_cc[VKILL] = 025; /* ^X */ - termios.c_cc[VEOF] = 04; /* ^D */ - termios.c_cc[VSTART] = 021; /* ^Q */ - termios.c_cc[VSTOP] = 023; /* ^S */ - termios.c_cc[VSUSP] = 032; /* ^Z */ - termios.c_cc[VLNEXT] = 026; /* ^V */ - termios.c_cc[VWERASE] = 027; /* ^W */ - termios.c_cc[VREPRINT] = 022; /* ^R */ - termios.c_cc[VEOL] = 0; - termios.c_cc[VEOL2] = 0; - - termios.c_cc[VTIME] = 0; - termios.c_cc[VMIN] = 1; - - if (tcsetattr(fd, TCSANOW, &termios) < 0) - r = -errno; - -finish: - /* Just in case, flush all crap out */ - tcflush(fd, TCIOFLUSH); - - return r; -} - -int reset_terminal(const char *name) { - _cleanup_close_ int fd = -1; - - fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - return reset_terminal_fd(fd, true); -} - -int open_terminal(const char *name, int mode) { - int fd, r; - unsigned c = 0; - - /* - * If a TTY is in the process of being closed opening it might - * cause EIO. This is horribly awful, but unlikely to be - * changed in the kernel. Hence we work around this problem by - * retrying a couple of times. - * - * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245 - */ - - assert(!(mode & O_CREAT)); - - for (;;) { - fd = open(name, mode, 0); - if (fd >= 0) - break; - - if (errno != EIO) - return -errno; - - /* Max 1s in total */ - if (c >= 20) - return -errno; - - usleep(50 * USEC_PER_MSEC); - c++; - } - - r = isatty(fd); - if (r < 0) { - safe_close(fd); - return -errno; - } - - if (!r) { - safe_close(fd); - return -ENOTTY; - } - - return fd; -} - -int flush_fd(int fd) { - struct pollfd pollfd = { - .fd = fd, - .events = POLLIN, - }; - - for (;;) { - char buf[LINE_MAX]; - ssize_t l; - int r; - - r = poll(&pollfd, 1, 0); - if (r < 0) { - if (errno == EINTR) - continue; - - return -errno; - - } else if (r == 0) - return 0; - - l = read(fd, buf, sizeof(buf)); - if (l < 0) { - - if (errno == EINTR) - continue; - - if (errno == EAGAIN) - return 0; - - return -errno; - } else if (l == 0) - return 0; - } -} - -int acquire_terminal( - const char *name, - bool fail, - bool force, - bool ignore_tiocstty_eperm, - usec_t timeout) { - - int fd = -1, notify = -1, r = 0, wd = -1; - usec_t ts = 0; - - assert(name); - - /* We use inotify to be notified when the tty is closed. We - * create the watch before checking if we can actually acquire - * it, so that we don't lose any event. - * - * Note: strictly speaking this actually watches for the - * device being closed, it does *not* really watch whether a - * tty loses its controlling process. However, unless some - * rogue process uses TIOCNOTTY on /dev/tty *after* closing - * its tty otherwise this will not become a problem. As long - * as the administrator makes sure not configure any service - * on the same tty as an untrusted user this should not be a - * problem. (Which he probably should not do anyway.) */ - - if (timeout != USEC_INFINITY) - ts = now(CLOCK_MONOTONIC); - - if (!fail && !force) { - notify = inotify_init1(IN_CLOEXEC | (timeout != USEC_INFINITY ? IN_NONBLOCK : 0)); - if (notify < 0) { - r = -errno; - goto fail; - } - - wd = inotify_add_watch(notify, name, IN_CLOSE); - if (wd < 0) { - r = -errno; - goto fail; - } - } - - for (;;) { - struct sigaction sa_old, sa_new = { - .sa_handler = SIG_IGN, - .sa_flags = SA_RESTART, - }; - - if (notify >= 0) { - r = flush_fd(notify); - if (r < 0) - goto fail; - } - - /* We pass here O_NOCTTY only so that we can check the return - * value TIOCSCTTY and have a reliable way to figure out if we - * successfully became the controlling process of the tty */ - fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed - * if we already own the tty. */ - assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0); - - /* First, try to get the tty */ - if (ioctl(fd, TIOCSCTTY, force) < 0) - r = -errno; - - assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0); - - /* Sometimes it makes sense to ignore TIOCSCTTY - * returning EPERM, i.e. when very likely we already - * are have this controlling terminal. */ - if (r < 0 && r == -EPERM && ignore_tiocstty_eperm) - r = 0; - - if (r < 0 && (force || fail || r != -EPERM)) { - goto fail; - } - - if (r >= 0) - break; - - assert(!fail); - assert(!force); - assert(notify >= 0); - - for (;;) { - uint8_t inotify_buffer[sizeof(struct inotify_event) + FILENAME_MAX]; - ssize_t l; - struct inotify_event *e; - - if (timeout != USEC_INFINITY) { - usec_t n; - - n = now(CLOCK_MONOTONIC); - if (ts + timeout < n) { - r = -ETIMEDOUT; - goto fail; - } - - r = fd_wait_for_event(fd, POLLIN, ts + timeout - n); - if (r < 0) - goto fail; - - if (r == 0) { - r = -ETIMEDOUT; - goto fail; - } - } - - l = read(notify, inotify_buffer, sizeof(inotify_buffer)); - if (l < 0) { - - if (errno == EINTR || errno == EAGAIN) - continue; - - r = -errno; - goto fail; - } - - e = (struct inotify_event*) inotify_buffer; - - while (l > 0) { - size_t step; - - if (e->wd != wd || !(e->mask & IN_CLOSE)) { - r = -EIO; - goto fail; - } - - step = sizeof(struct inotify_event) + e->len; - assert(step <= (size_t) l); - - e = (struct inotify_event*) ((uint8_t*) e + step); - l -= step; - } - - break; - } - - /* We close the tty fd here since if the old session - * ended our handle will be dead. It's important that - * we do this after sleeping, so that we don't enter - * an endless loop. */ - fd = safe_close(fd); - } - - safe_close(notify); - - r = reset_terminal_fd(fd, true); - if (r < 0) - log_warning("Failed to reset terminal: %s", strerror(-r)); - - return fd; - -fail: - safe_close(fd); - safe_close(notify); - - return r; -} - -int release_terminal(void) { - static const struct sigaction sa_new = { - .sa_handler = SIG_IGN, - .sa_flags = SA_RESTART, - }; - - _cleanup_close_ int fd = -1; - struct sigaction sa_old; - int r = 0; - - fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_NDELAY|O_CLOEXEC); - if (fd < 0) - return -errno; - - /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed - * by our own TIOCNOTTY */ - assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0); - - if (ioctl(fd, TIOCNOTTY) < 0) - r = -errno; - - assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0); - - return r; -} - -int sigaction_many(const struct sigaction *sa, ...) { - va_list ap; - int r = 0, sig; - - va_start(ap, sa); - while ((sig = va_arg(ap, int)) > 0) - if (sigaction(sig, sa, NULL) < 0) - r = -errno; - va_end(ap); - - return r; -} - -int ignore_signals(int sig, ...) { - struct sigaction sa = { - .sa_handler = SIG_IGN, - .sa_flags = SA_RESTART, - }; - va_list ap; - int r = 0; - - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - - va_start(ap, sig); - while ((sig = va_arg(ap, int)) > 0) - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - va_end(ap); - - return r; -} - -int default_signals(int sig, ...) { - struct sigaction sa = { - .sa_handler = SIG_DFL, - .sa_flags = SA_RESTART, - }; - va_list ap; - int r = 0; - - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - - va_start(ap, sig); - while ((sig = va_arg(ap, int)) > 0) - if (sigaction(sig, &sa, NULL) < 0) - r = -errno; - va_end(ap); - - return r; -} - -void safe_close_pair(int p[]) { - assert(p); - - if (p[0] == p[1]) { - /* Special case pairs which use the same fd in both - * directions... */ - p[0] = p[1] = safe_close(p[0]); - return; - } - - p[0] = safe_close(p[0]); - p[1] = safe_close(p[1]); -} -#endif - -ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { - uint8_t *p = buf; - ssize_t n = 0; - - assert(fd >= 0); - assert(buf); - - while (nbytes > 0) { - ssize_t k; - - k = read(fd, p, nbytes); - if (k < 0 && errno == EINTR) - continue; - - if (k < 0 && errno == EAGAIN && do_poll) { - - /* We knowingly ignore any return value here, - * and expect that any error/EOF is reported - * via read() */ - - fd_wait_for_event(fd, POLLIN, USEC_INFINITY); - continue; - } - - if (k <= 0) - return n > 0 ? n : (k < 0 ? -errno : 0); - - p += k; - nbytes -= k; - n += k; - } - - return n; -} - -#if 0 /* NM_IGNORED */ -ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { - const uint8_t *p = buf; - ssize_t n = 0; - - assert(fd >= 0); - assert(buf); - - while (nbytes > 0) { - ssize_t k; - - k = write(fd, p, nbytes); - if (k < 0 && errno == EINTR) - continue; - - if (k < 0 && errno == EAGAIN && do_poll) { - - /* We knowingly ignore any return value here, - * and expect that any error/EOF is reported - * via write() */ - - fd_wait_for_event(fd, POLLOUT, USEC_INFINITY); - continue; - } - - if (k <= 0) - return n > 0 ? n : (k < 0 ? -errno : 0); - - p += k; - nbytes -= k; - n += k; - } - - return n; -} - -int parse_size(const char *t, off_t base, off_t *size) { - - /* Soo, sometimes we want to parse IEC binary suffxies, and - * sometimes SI decimal suffixes. This function can parse - * both. Which one is the right way depends on the - * context. Wikipedia suggests that SI is customary for - * hardrware metrics and network speeds, while IEC is - * customary for most data sizes used by software and volatile - * (RAM) memory. Hence be careful which one you pick! - * - * In either case we use just K, M, G as suffix, and not Ki, - * Mi, Gi or so (as IEC would suggest). That's because that's - * frickin' ugly. But this means you really need to make sure - * to document which base you are parsing when you use this - * call. */ - - struct table { - const char *suffix; - unsigned long long factor; - }; - - static const struct table iec[] = { - { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, - { "G", 1024ULL*1024ULL*1024ULL }, - { "M", 1024ULL*1024ULL }, - { "K", 1024ULL }, - { "B", 1 }, - { "", 1 }, - }; - - static const struct table si[] = { - { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, - { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, - { "T", 1000ULL*1000ULL*1000ULL*1000ULL }, - { "G", 1000ULL*1000ULL*1000ULL }, - { "M", 1000ULL*1000ULL }, - { "K", 1000ULL }, - { "B", 1 }, - { "", 1 }, - }; - - const struct table *table; - const char *p; - unsigned long long r = 0; - unsigned n_entries, start_pos = 0; - - assert(t); - assert(base == 1000 || base == 1024); - assert(size); - - if (base == 1000) { - table = si; - n_entries = ELEMENTSOF(si); - } else { - table = iec; - n_entries = ELEMENTSOF(iec); - } - - p = t; - do { - long long l; - unsigned long long l2; - double frac = 0; - char *e; - unsigned i; - - errno = 0; - l = strtoll(p, &e, 10); - - if (errno > 0) - return -errno; - - if (l < 0) - return -ERANGE; - - if (e == p) - return -EINVAL; - - if (*e == '.') { - e++; - if (*e >= '0' && *e <= '9') { - char *e2; - - /* strotoull itself would accept space/+/- */ - l2 = strtoull(e, &e2, 10); - - if (errno == ERANGE) - return -errno; - - /* Ignore failure. E.g. 10.M is valid */ - frac = l2; - for (; e < e2; e++) - frac /= 10; - } - } - - e += strspn(e, WHITESPACE); - - for (i = start_pos; i < n_entries; i++) - if (startswith(e, table[i].suffix)) { - unsigned long long tmp; - if ((unsigned long long) l + (frac > 0) > ULLONG_MAX / table[i].factor) - return -ERANGE; - tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor); - if (tmp > ULLONG_MAX - r) - return -ERANGE; - - r += tmp; - if ((unsigned long long) (off_t) r != r) - return -ERANGE; - - p = e + strlen(table[i].suffix); - - start_pos = i + 1; - break; - } - - if (i >= n_entries) - return -EINVAL; - - } while (*p); - - *size = r; - - return 0; -} - -int make_stdio(int fd) { - int r, s, t; - - assert(fd >= 0); - - r = dup3(fd, STDIN_FILENO, 0); - s = dup3(fd, STDOUT_FILENO, 0); - t = dup3(fd, STDERR_FILENO, 0); - - if (fd >= 3) - safe_close(fd); - - if (r < 0 || s < 0 || t < 0) - return -errno; - - /* We rely here that the new fd has O_CLOEXEC not set */ - - return 0; -} - -int make_null_stdio(void) { - int null_fd; - - null_fd = open("/dev/null", O_RDWR|O_NOCTTY); - if (null_fd < 0) - return -errno; - - return make_stdio(null_fd); -} - -bool is_device_path(const char *path) { - - /* Returns true on paths that refer to a device, either in - * sysfs or in /dev */ - - return - path_startswith(path, "/dev/") || - path_startswith(path, "/sys/"); -} - -int dir_is_empty(const char *path) { - _cleanup_closedir_ DIR *d; - - d = opendir(path); - if (!d) - return -errno; - - for (;;) { - struct dirent *de; - - errno = 0; - de = readdir(d); - if (!de && errno != 0) - return -errno; - - if (!de) - return 1; - - if (!ignore_file(de->d_name)) - return 0; - } -} - -char* dirname_malloc(const char *path) { - char *d, *dir, *dir2; - - d = strdup(path); - if (!d) - return NULL; - dir = dirname(d); - assert(dir); - - if (dir != d) { - dir2 = strdup(dir); - free(d); - return dir2; - } - - return dir; -} -#endif - -int dev_urandom(void *p, size_t n) { -#if 0 /* NM_IGNORED */ - static int have_syscall = -1; - int r, fd; - ssize_t k; - - /* Gathers some randomness from the kernel. This call will - * never block, and will always return some data from the - * kernel, regardless if the random pool is fully initialized - * or not. It thus makes no guarantee for the quality of the - * returned entropy, but is good enough for or usual usecases - * of seeding the hash functions for hashtable */ - - /* Use the getrandom() syscall unless we know we don't have - * it, or when the requested size is too large for it. */ - if (have_syscall != 0 || (size_t) (int) n != n) { - r = getrandom(p, n, GRND_NONBLOCK); - if (r == (int) n) { - have_syscall = true; - return 0; - } - - if (r < 0) { - if (errno == ENOSYS) - /* we lack the syscall, continue with - * reading from /dev/urandom */ - have_syscall = false; - else if (errno == EAGAIN) - /* not enough entropy for now. Let's - * remember to use the syscall the - * next time, again, but also read - * from /dev/urandom for now, which - * doesn't care about the current - * amount of entropy. */ - have_syscall = true; - else - return -errno; - } else - /* too short read? */ - return -EIO; - } -#else /* NM IGNORED */ - int fd; - ssize_t k; -#endif - - fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return errno == ENOENT ? -ENOSYS : -errno; - - k = loop_read(fd, p, n, true); - safe_close(fd); - - if (k < 0) - return (int) k; - if ((size_t) k != n) - return -EIO; - - return 0; -} - -void initialize_srand(void) { - static bool srand_called = false; - unsigned x; -#ifdef HAVE_SYS_AUXV_H - void *auxv; -#endif - - if (srand_called) - return; - - x = 0; - -#ifdef HAVE_SYS_AUXV_H - /* The kernel provides us with a bit of entropy in auxv, so - * let's try to make use of that to seed the pseudo-random - * generator. It's better than nothing... */ - - auxv = (void*) getauxval(AT_RANDOM); - if (auxv) - x ^= *(unsigned*) auxv; -#endif - - x ^= (unsigned) now(CLOCK_REALTIME); - x ^= (unsigned) gettid(); - - srand(x); - srand_called = true; -} - -void random_bytes(void *p, size_t n) { - uint8_t *q; - int r; - - r = dev_urandom(p, n); - if (r >= 0) - return; - - /* If some idiot made /dev/urandom unavailable to us, he'll - * get a PRNG instead. */ - - initialize_srand(); - - for (q = p; q < (uint8_t*) p + n; q ++) - *q = rand(); -} - -#if 0 /* NM_IGNORED */ -void rename_process(const char name[8]) { - assert(name); - - /* This is a like a poor man's setproctitle(). It changes the - * comm field, argv[0], and also the glibc's internally used - * name of the process. For the first one a limit of 16 chars - * applies, to the second one usually one of 10 (i.e. length - * of "/sbin/init"), to the third one one of 7 (i.e. length of - * "systemd"). If you pass a longer string it will be - * truncated */ - - prctl(PR_SET_NAME, name); - - if (program_invocation_name) - strncpy(program_invocation_name, name, strlen(program_invocation_name)); - - if (saved_argc > 0) { - int i; - - if (saved_argv[0]) - strncpy(saved_argv[0], name, strlen(saved_argv[0])); - - for (i = 1; i < saved_argc; i++) { - if (!saved_argv[i]) - break; - - memzero(saved_argv[i], strlen(saved_argv[i])); - } - } -} - -void sigset_add_many(sigset_t *ss, ...) { - va_list ap; - int sig; - - assert(ss); - - va_start(ap, ss); - while ((sig = va_arg(ap, int)) > 0) - assert_se(sigaddset(ss, sig) == 0); - va_end(ap); -} - -int sigprocmask_many(int how, ...) { - va_list ap; - sigset_t ss; - int sig; - - assert_se(sigemptyset(&ss) == 0); - - va_start(ap, how); - while ((sig = va_arg(ap, int)) > 0) - assert_se(sigaddset(&ss, sig) == 0); - va_end(ap); - - if (sigprocmask(how, &ss, NULL) < 0) - return -errno; - - return 0; -} - -char* gethostname_malloc(void) { - struct utsname u; - - assert_se(uname(&u) >= 0); - - if (!isempty(u.nodename) && !streq(u.nodename, "(none)")) - return strdup(u.nodename); - - return strdup(u.sysname); -} - -bool hostname_is_set(void) { - struct utsname u; - - assert_se(uname(&u) >= 0); - - return !isempty(u.nodename) && !streq(u.nodename, "(none)"); -} - -char *lookup_uid(uid_t uid) { - long bufsize; - char *name; - _cleanup_free_ char *buf = NULL; - struct passwd pwbuf, *pw = NULL; - - /* Shortcut things to avoid NSS lookups */ - if (uid == 0) - return strdup("root"); - - bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); - if (bufsize <= 0) - bufsize = 4096; - - buf = malloc(bufsize); - if (!buf) - return NULL; - - if (getpwuid_r(uid, &pwbuf, buf, bufsize, &pw) == 0 && pw) - return strdup(pw->pw_name); - - if (asprintf(&name, UID_FMT, uid) < 0) - return NULL; - - return name; -} - -char* getlogname_malloc(void) { - uid_t uid; - struct stat st; - - if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0) - uid = st.st_uid; - else - uid = getuid(); - - return lookup_uid(uid); -} - -char *getusername_malloc(void) { - const char *e; - - e = getenv("USER"); - if (e) - return strdup(e); - - return lookup_uid(getuid()); -} - -int getttyname_malloc(int fd, char **r) { - char path[PATH_MAX], *c; - int k; - - assert(r); - - k = ttyname_r(fd, path, sizeof(path)); - if (k > 0) - return -k; - - char_array_0(path); - - c = strdup(startswith(path, "/dev/") ? path + 5 : path); - if (!c) - return -ENOMEM; - - *r = c; - return 0; -} - -int getttyname_harder(int fd, char **r) { - int k; - char *s; - - k = getttyname_malloc(fd, &s); - if (k < 0) - return k; - - if (streq(s, "tty")) { - free(s); - return get_ctty(0, NULL, r); - } - - *r = s; - return 0; -} - -int get_ctty_devnr(pid_t pid, dev_t *d) { - int r; - _cleanup_free_ char *line = NULL; - const char *p; - unsigned long ttynr; - - assert(pid >= 0); - - p = procfs_file_alloca(pid, "stat"); - r = read_one_line_file(p, &line); - if (r < 0) - return r; - - p = strrchr(line, ')'); - if (!p) - return -EIO; - - p++; - - if (sscanf(p, " " - "%*c " /* state */ - "%*d " /* ppid */ - "%*d " /* pgrp */ - "%*d " /* session */ - "%lu ", /* ttynr */ - &ttynr) != 1) - return -EIO; - - if (major(ttynr) == 0 && minor(ttynr) == 0) - return -ENOENT; - - if (d) - *d = (dev_t) ttynr; - - return 0; -} - -int get_ctty(pid_t pid, dev_t *_devnr, char **r) { - char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL; - _cleanup_free_ char *s = NULL; - const char *p; - dev_t devnr; - int k; - - assert(r); - - k = get_ctty_devnr(pid, &devnr); - if (k < 0) - return k; - - sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr)); - - k = readlink_malloc(fn, &s); - if (k < 0) { - - if (k != -ENOENT) - return k; - - /* This is an ugly hack */ - if (major(devnr) == 136) { - asprintf(&b, "pts/%u", minor(devnr)); - goto finish; - } - - /* Probably something like the ptys which have no - * symlink in /dev/char. Let's return something - * vaguely useful. */ - - b = strdup(fn + 5); - goto finish; - } - - if (startswith(s, "/dev/")) - p = s + 5; - else if (startswith(s, "../")) - p = s + 3; - else - p = s; - - b = strdup(p); - -finish: - if (!b) - return -ENOMEM; - - *r = b; - if (_devnr) - *_devnr = devnr; - - return 0; -} - -int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) { - _cleanup_closedir_ DIR *d = NULL; - int ret = 0; - - assert(fd >= 0); - - /* This returns the first error we run into, but nevertheless - * tries to go on. This closes the passed fd. */ - - d = fdopendir(fd); - if (!d) { - safe_close(fd); - - return errno == ENOENT ? 0 : -errno; - } - - for (;;) { - struct dirent *de; - bool is_dir, keep_around; - struct stat st; - int r; - - errno = 0; - de = readdir(d); - if (!de) { - if (errno != 0 && ret == 0) - ret = -errno; - return ret; - } - - if (streq(de->d_name, ".") || streq(de->d_name, "..")) - continue; - - if (de->d_type == DT_UNKNOWN || - honour_sticky || - (de->d_type == DT_DIR && root_dev)) { - if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; - continue; - } - - is_dir = S_ISDIR(st.st_mode); - keep_around = - honour_sticky && - (st.st_uid == 0 || st.st_uid == getuid()) && - (st.st_mode & S_ISVTX); - } else { - is_dir = de->d_type == DT_DIR; - keep_around = false; - } - - if (is_dir) { - int subdir_fd; - - /* if root_dev is set, remove subdirectories only, if device is same as dir */ - if (root_dev && st.st_dev != root_dev->st_dev) - continue; - - subdir_fd = openat(fd, de->d_name, - O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); - if (subdir_fd < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; - continue; - } - - r = rm_rf_children_dangerous(subdir_fd, only_dirs, honour_sticky, root_dev); - if (r < 0 && ret == 0) - ret = r; - - if (!keep_around) - if (unlinkat(fd, de->d_name, AT_REMOVEDIR) < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; - } - - } else if (!only_dirs && !keep_around) { - - if (unlinkat(fd, de->d_name, 0) < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; - } - } - } -} - -_pure_ static int is_temporary_fs(struct statfs *s) { - assert(s); - - return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) || - F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC); -} - -int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev) { - struct statfs s; - - assert(fd >= 0); - - if (fstatfs(fd, &s) < 0) { - safe_close(fd); - return -errno; - } - - /* We refuse to clean disk file systems with this call. This - * is extra paranoia just to be sure we never ever remove - * non-state data */ - if (!is_temporary_fs(&s)) { - log_error("Attempted to remove disk file system, and we can't allow that."); - safe_close(fd); - return -EPERM; - } - - return rm_rf_children_dangerous(fd, only_dirs, honour_sticky, root_dev); -} - -static int file_is_priv_sticky(const char *p) { - struct stat st; - - assert(p); - - if (lstat(p, &st) < 0) - return -errno; - - return - (st.st_uid == 0 || st.st_uid == getuid()) && - (st.st_mode & S_ISVTX); -} - -static int rm_rf_internal(const char *path, bool only_dirs, bool delete_root, bool honour_sticky, bool dangerous) { - int fd, r; - struct statfs s; - - assert(path); - - /* We refuse to clean the root file system with this - * call. This is extra paranoia to never cause a really - * seriously broken system. */ - if (path_equal(path, "/")) { - log_error("Attempted to remove entire root file system, and we can't allow that."); - return -EPERM; - } - - fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); - if (fd < 0) { - - if (errno != ENOTDIR) - return -errno; - - if (!dangerous) { - if (statfs(path, &s) < 0) - return -errno; - - if (!is_temporary_fs(&s)) { - log_error("Attempted to remove disk file system, and we can't allow that."); - return -EPERM; - } - } - - if (delete_root && !only_dirs) - if (unlink(path) < 0 && errno != ENOENT) - return -errno; - - return 0; - } - - if (!dangerous) { - if (fstatfs(fd, &s) < 0) { - safe_close(fd); - return -errno; - } - - if (!is_temporary_fs(&s)) { - log_error("Attempted to remove disk file system, and we can't allow that."); - safe_close(fd); - return -EPERM; - } - } - - r = rm_rf_children_dangerous(fd, only_dirs, honour_sticky, NULL); - if (delete_root) { - - if (honour_sticky && file_is_priv_sticky(path) > 0) - return r; - - if (rmdir(path) < 0 && errno != ENOENT) { - if (r == 0) - r = -errno; - } - } - - return r; -} - -int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) { - return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, false); -} - -int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool honour_sticky) { - return rm_rf_internal(path, only_dirs, delete_root, honour_sticky, true); -} - -int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { - assert(path); - - /* Under the assumption that we are running privileged we - * first change the access mode and only then hand out - * ownership to avoid a window where access is too open. */ - - if (mode != (mode_t) -1) - if (chmod(path, mode) < 0) - return -errno; - - if (uid != (uid_t) -1 || gid != (gid_t) -1) - if (chown(path, uid, gid) < 0) - return -errno; - - return 0; -} - -int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) { - assert(fd >= 0); - - /* Under the assumption that we are running privileged we - * first change the access mode and only then hand out - * ownership to avoid a window where access is too open. */ - - if (mode != (mode_t) -1) - if (fchmod(fd, mode) < 0) - return -errno; - - if (uid != (uid_t) -1 || gid != (gid_t) -1) - if (fchown(fd, uid, gid) < 0) - return -errno; - - return 0; -} - -cpu_set_t* cpu_set_malloc(unsigned *ncpus) { - cpu_set_t *r; - unsigned n = 1024; - - /* Allocates the cpuset in the right size */ - - for (;;) { - if (!(r = CPU_ALLOC(n))) - return NULL; - - if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), r) >= 0) { - CPU_ZERO_S(CPU_ALLOC_SIZE(n), r); - - if (ncpus) - *ncpus = n; - - return r; - } - - CPU_FREE(r); - - if (errno != EINVAL) - return NULL; - - n *= 2; - } -} - -int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) { - static const char status_indent[] = " "; /* "[" STATUS "] " */ - _cleanup_free_ char *s = NULL; - _cleanup_close_ int fd = -1; - struct iovec iovec[6] = {}; - int n = 0; - static bool prev_ephemeral; - - assert(format); - - /* This is independent of logging, as status messages are - * optional and go exclusively to the console. */ - - if (vasprintf(&s, format, ap) < 0) - return log_oom(); - - fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - if (ellipse) { - char *e; - size_t emax, sl; - int c; - - c = fd_columns(fd); - if (c <= 0) - c = 80; - - sl = status ? sizeof(status_indent)-1 : 0; - - emax = c - sl - 1; - if (emax < 3) - emax = 3; - - e = ellipsize(s, emax, 50); - if (e) { - free(s); - s = e; - } - } - - if (prev_ephemeral) - IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE); - prev_ephemeral = ephemeral; - - if (status) { - if (!isempty(status)) { - IOVEC_SET_STRING(iovec[n++], "["); - IOVEC_SET_STRING(iovec[n++], status); - IOVEC_SET_STRING(iovec[n++], "] "); - } else - IOVEC_SET_STRING(iovec[n++], status_indent); - } - - IOVEC_SET_STRING(iovec[n++], s); - if (!ephemeral) - IOVEC_SET_STRING(iovec[n++], "\n"); - - if (writev(fd, iovec, n) < 0) - return -errno; - - return 0; -} - -int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) { - va_list ap; - int r; - - assert(format); - - va_start(ap, format); - r = status_vprintf(status, ellipse, ephemeral, format, ap); - va_end(ap); - - return r; -} - -char *replace_env(const char *format, char **env) { - enum { - WORD, - CURLY, - VARIABLE - } state = WORD; - - const char *e, *word = format; - char *r = NULL, *k; - - assert(format); - - for (e = format; *e; e ++) { - - switch (state) { - - case WORD: - if (*e == '$') - state = CURLY; - break; - - case CURLY: - if (*e == '{') { - k = strnappend(r, word, e-word-1); - if (!k) - goto fail; - - free(r); - r = k; - - word = e-1; - state = VARIABLE; - - } else if (*e == '$') { - k = strnappend(r, word, e-word); - if (!k) - goto fail; - - free(r); - r = k; - - word = e+1; - state = WORD; - } else - state = WORD; - break; - - case VARIABLE: - if (*e == '}') { - const char *t; - - t = strempty(strv_env_get_n(env, word+2, e-word-2)); - - k = strappend(r, t); - if (!k) - goto fail; - - free(r); - r = k; - - word = e+1; - state = WORD; - } - break; - } - } - - k = strnappend(r, word, e-word); - if (!k) - goto fail; - - free(r); - return k; - -fail: - free(r); - return NULL; -} - -#if 0 /* NM_IGNORED */ -char **replace_env_argv(char **argv, char **env) { - char **ret, **i; - unsigned k = 0, l = 0; - - l = strv_length(argv); - - ret = new(char*, l+1); - if (!ret) - return NULL; - - STRV_FOREACH(i, argv) { - - /* If $FOO appears as single word, replace it by the split up variable */ - if ((*i)[0] == '$' && (*i)[1] != '{') { - char *e; - char **w, **m; - unsigned q; - - e = strv_env_get(env, *i+1); - if (e) { - int r; - - r = strv_split_quoted(&m, e, true); - if (r < 0) { - ret[k] = NULL; - strv_free(ret); - return NULL; - } - } else - m = NULL; - - q = strv_length(m); - l = l + q - 1; - - w = realloc(ret, sizeof(char*) * (l+1)); - if (!w) { - ret[k] = NULL; - strv_free(ret); - strv_free(m); - return NULL; - } - - ret = w; - if (m) { - memcpy(ret + k, m, q * sizeof(char*)); - free(m); - } - - k += q; - continue; - } - - /* If ${FOO} appears as part of a word, replace it by the variable as-is */ - ret[k] = replace_env(*i, env); - if (!ret[k]) { - strv_free(ret); - return NULL; - } - k++; - } - - ret[k] = NULL; - return ret; -} -#endif - -int fd_columns(int fd) { - struct winsize ws = {}; - - if (ioctl(fd, TIOCGWINSZ, &ws) < 0) - return -errno; - - if (ws.ws_col <= 0) - return -EIO; - - return ws.ws_col; -} - -unsigned columns(void) { - const char *e; - int c; - - if (_likely_(cached_columns > 0)) - return cached_columns; - - c = 0; - e = getenv("COLUMNS"); - if (e) - (void) safe_atoi(e, &c); - - if (c <= 0) - c = fd_columns(STDOUT_FILENO); - - if (c <= 0) - c = 80; - - cached_columns = c; - return c; -} - -int fd_lines(int fd) { - struct winsize ws = {}; - - if (ioctl(fd, TIOCGWINSZ, &ws) < 0) - return -errno; - - if (ws.ws_row <= 0) - return -EIO; - - return ws.ws_row; -} - -unsigned lines(void) { - const char *e; - unsigned l; - - if (_likely_(cached_lines > 0)) - return cached_lines; - - l = 0; - e = getenv("LINES"); - if (e) - (void) safe_atou(e, &l); - - if (l <= 0) - l = fd_lines(STDOUT_FILENO); - - if (l <= 0) - l = 24; - - cached_lines = l; - return cached_lines; -} - -/* intended to be used as a SIGWINCH sighandler */ -void columns_lines_cache_reset(int signum) { - cached_columns = 0; - cached_lines = 0; -} - -bool on_tty(void) { - static int cached_on_tty = -1; - - if (_unlikely_(cached_on_tty < 0)) - cached_on_tty = isatty(STDOUT_FILENO) > 0; - - return cached_on_tty; -} - -int files_same(const char *filea, const char *fileb) { - struct stat a, b; - - if (stat(filea, &a) < 0) - return -errno; - - if (stat(fileb, &b) < 0) - return -errno; - - return a.st_dev == b.st_dev && - a.st_ino == b.st_ino; -} - -int running_in_chroot(void) { - int ret; - - ret = files_same("/proc/1/root", "/"); - if (ret < 0) - return ret; - - return ret == 0; -} - -static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { - size_t x; - char *r; - - assert(s); - assert(percent <= 100); - assert(new_length >= 3); - - if (old_length <= 3 || old_length <= new_length) - return strndup(s, old_length); - - r = new0(char, new_length+1); - if (!r) - return NULL; - - x = (new_length * percent) / 100; - - if (x > new_length - 3) - x = new_length - 3; - - memcpy(r, s, x); - r[x] = '.'; - r[x+1] = '.'; - r[x+2] = '.'; - memcpy(r + x + 3, - s + old_length - (new_length - x - 3), - new_length - x - 3); - - return r; -} - -char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { - size_t x; - char *e; - const char *i, *j; - unsigned k, len, len2; - - assert(s); - assert(percent <= 100); - assert(new_length >= 3); - - /* if no multibyte characters use ascii_ellipsize_mem for speed */ - if (ascii_is_valid(s)) - return ascii_ellipsize_mem(s, old_length, new_length, percent); - - if (old_length <= 3 || old_length <= new_length) - return strndup(s, old_length); - - x = (new_length * percent) / 100; - - if (x > new_length - 3) - x = new_length - 3; - - k = 0; - for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) { - int c; - - c = utf8_encoded_to_unichar(i); - if (c < 0) - return NULL; - k += unichar_iswide(c) ? 2 : 1; - } - - if (k > x) /* last character was wide and went over quota */ - x ++; - - for (j = s + old_length; k < new_length && j > i; ) { - int c; - - j = utf8_prev_char(j); - c = utf8_encoded_to_unichar(j); - if (c < 0) - return NULL; - k += unichar_iswide(c) ? 2 : 1; - } - assert(i <= j); - - /* we don't actually need to ellipsize */ - if (i == j) - return memdup(s, old_length + 1); - - /* make space for ellipsis */ - j = utf8_next_char(j); - - len = i - s; - len2 = s + old_length - j; - e = new(char, len + 3 + len2 + 1); - if (!e) - return NULL; - - /* - printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n", - old_length, new_length, x, len, len2, k); - */ - - memcpy(e, s, len); - e[len] = 0xe2; /* tri-dot ellipsis: … */ - e[len + 1] = 0x80; - e[len + 2] = 0xa6; - - memcpy(e + len + 3, j, len2 + 1); - - return e; -} - -char *ellipsize(const char *s, size_t length, unsigned percent) { - return ellipsize_mem(s, strlen(s), length, percent); -} - -int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) { - _cleanup_close_ int fd = -1; - int r; - - assert(path); - - if (parents) - mkdir_parents(path, 0755); - - fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644); - if (fd < 0) - return -errno; - - if (mode > 0) { - r = fchmod(fd, mode); - if (r < 0) - return -errno; - } - - if (uid != (uid_t) -1 || gid != (gid_t) -1) { - r = fchown(fd, uid, gid); - if (r < 0) - return -errno; - } - - if (stamp != USEC_INFINITY) { - struct timespec ts[2]; - - timespec_store(&ts[0], stamp); - ts[1] = ts[0]; - r = futimens(fd, ts); - } else - r = futimens(fd, NULL); - if (r < 0) - return -errno; - - return 0; -} - -int touch(const char *path) { - return touch_file(path, false, USEC_INFINITY, (uid_t) -1, (gid_t) -1, 0); -} - -char *unquote(const char *s, const char* quotes) { - size_t l; - assert(s); - - /* This is rather stupid, simply removes the heading and - * trailing quotes if there is one. Doesn't care about - * escaping or anything. We should make this smarter one - * day...*/ - - l = strlen(s); - if (l < 2) - return strdup(s); - - if (strchr(quotes, s[0]) && s[l-1] == s[0]) - return strndup(s+1, l-2); - - return strdup(s); -} - -char *normalize_env_assignment(const char *s) { - _cleanup_free_ char *value = NULL; - const char *eq; - char *p, *name; - - eq = strchr(s, '='); - if (!eq) { - char *r, *t; - - r = strdup(s); - if (!r) - return NULL; - - t = strstrip(r); - if (t != r) - memmove(r, t, strlen(t) + 1); - - return r; - } - - name = strndupa(s, eq - s); - p = strdupa(eq + 1); - - value = unquote(strstrip(p), QUOTES); - if (!value) - return NULL; - - return strjoin(strstrip(name), "=", value, NULL); -} - -int wait_for_terminate(pid_t pid, siginfo_t *status) { - siginfo_t dummy; - - assert(pid >= 1); - - if (!status) - status = &dummy; - - for (;;) { - zero(*status); - - if (waitid(P_PID, pid, status, WEXITED) < 0) { - - if (errno == EINTR) - continue; - - return -errno; - } - - return 0; - } -} - -/* - * Return values: - * < 0 : wait_for_terminate() failed to get the state of the - * process, the process was terminated by a signal, or - * failed for an unknown reason. - * >=0 : The process terminated normally, and its exit code is - * returned. - * - * That is, success is indicated by a return value of zero, and an - * error is indicated by a non-zero value. - */ -int wait_for_terminate_and_warn(const char *name, pid_t pid) { - int r; - siginfo_t status; - - assert(name); - assert(pid > 1); - - r = wait_for_terminate(pid, &status); - if (r < 0) { - log_warning("Failed to wait for %s: %s", name, strerror(-r)); - return r; - } - - if (status.si_code == CLD_EXITED) { - if (status.si_status != 0) { - log_warning("%s failed with error code %i.", name, status.si_status); - return status.si_status; - } - - log_debug("%s succeeded.", name); - return 0; - - } else if (status.si_code == CLD_KILLED || - status.si_code == CLD_DUMPED) { - - log_warning("%s terminated by signal %s.", name, signal_to_string(status.si_status)); - return -EPROTO; - } - - log_warning("%s failed due to unknown reason.", name); - return -EPROTO; -} - -noreturn void freeze(void) { - - /* Make sure nobody waits for us on a socket anymore */ - close_all_fds(NULL, 0); - - sync(); - - for (;;) - pause(); -} - -bool null_or_empty(struct stat *st) { - assert(st); - - if (S_ISREG(st->st_mode) && st->st_size <= 0) - return true; - - if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) - return true; - - return false; -} - -int null_or_empty_path(const char *fn) { - struct stat st; - - assert(fn); - - if (stat(fn, &st) < 0) - return -errno; - - return null_or_empty(&st); -} - -int null_or_empty_fd(int fd) { - struct stat st; - - assert(fd >= 0); - - if (fstat(fd, &st) < 0) - return -errno; - - return null_or_empty(&st); -} - -DIR *xopendirat(int fd, const char *name, int flags) { - int nfd; - DIR *d; - - assert(!(flags & O_CREAT)); - - nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0); - if (nfd < 0) - return NULL; - - d = fdopendir(nfd); - if (!d) { - safe_close(nfd); - return NULL; - } - - return d; -} - -int signal_from_string_try_harder(const char *s) { - int signo; - assert(s); - - signo = signal_from_string(s); - if (signo <= 0) - if (startswith(s, "SIG")) - return signal_from_string(s+3); - - return signo; -} - -static char *tag_to_udev_node(const char *tagvalue, const char *by) { - _cleanup_free_ char *t = NULL, *u = NULL; - size_t enc_len; - - u = unquote(tagvalue, "\"\'"); - if (!u) - return NULL; - - enc_len = strlen(u) * 4 + 1; - t = new(char, enc_len); - if (!t) - return NULL; - - if (encode_devnode_name(u, t, enc_len) < 0) - return NULL; - - return strjoin("/dev/disk/by-", by, "/", t, NULL); -} - -char *fstab_node_to_udev_node(const char *p) { - assert(p); - - if (startswith(p, "LABEL=")) - return tag_to_udev_node(p+6, "label"); - - if (startswith(p, "UUID=")) - return tag_to_udev_node(p+5, "uuid"); - - if (startswith(p, "PARTUUID=")) - return tag_to_udev_node(p+9, "partuuid"); - - if (startswith(p, "PARTLABEL=")) - return tag_to_udev_node(p+10, "partlabel"); - - return strdup(p); -} - -bool tty_is_vc(const char *tty) { - assert(tty); - - return vtnr_from_tty(tty) >= 0; -} - -bool tty_is_console(const char *tty) { - assert(tty); - - if (startswith(tty, "/dev/")) - tty += 5; - - return streq(tty, "console"); -} - -int vtnr_from_tty(const char *tty) { - int i, r; - - assert(tty); - - if (startswith(tty, "/dev/")) - tty += 5; - - if (!startswith(tty, "tty") ) - return -EINVAL; - - if (tty[3] < '0' || tty[3] > '9') - return -EINVAL; - - r = safe_atoi(tty+3, &i); - if (r < 0) - return r; - - if (i < 0 || i > 63) - return -EINVAL; - - return i; -} - -char *resolve_dev_console(char **active) { - char *tty; - - /* Resolve where /dev/console is pointing to, if /sys is actually ours - * (i.e. not read-only-mounted which is a sign for container setups) */ - - if (path_is_read_only_fs("/sys") > 0) - return NULL; - - if (read_one_line_file("/sys/class/tty/console/active", active) < 0) - return NULL; - - /* If multiple log outputs are configured the last one is what - * /dev/console points to */ - tty = strrchr(*active, ' '); - if (tty) - tty++; - else - tty = *active; - - if (streq(tty, "tty0")) { - char *tmp; - - /* Get the active VC (e.g. tty1) */ - if (read_one_line_file("/sys/class/tty/tty0/active", &tmp) >= 0) { - free(*active); - tty = *active = tmp; - } - } - - return tty; -} - -bool tty_is_vc_resolve(const char *tty) { - _cleanup_free_ char *active = NULL; - - assert(tty); - - if (startswith(tty, "/dev/")) - tty += 5; - - if (streq(tty, "console")) { - tty = resolve_dev_console(&active); - if (!tty) - return false; - } - - return tty_is_vc(tty); -} - -const char *default_term_for_tty(const char *tty) { - assert(tty); - - return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt102"; -} - -bool dirent_is_file(const struct dirent *de) { - assert(de); - - if (ignore_file(de->d_name)) - return false; - - if (de->d_type != DT_REG && - de->d_type != DT_LNK && - de->d_type != DT_UNKNOWN) - return false; - - return true; -} - -bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) { - assert(de); - - if (de->d_type != DT_REG && - de->d_type != DT_LNK && - de->d_type != DT_UNKNOWN) - return false; - - if (ignore_file_allow_backup(de->d_name)) - return false; - - return endswith(de->d_name, suffix); -} - -void execute_directory(const char *directory, DIR *d, usec_t timeout, char *argv[]) { - pid_t executor_pid; - int r; - - assert(directory); - - /* Executes all binaries in a directory in parallel and waits - * for them to finish. Optionally a timeout is applied. */ - - executor_pid = fork(); - if (executor_pid < 0) { - log_error("Failed to fork: %m"); - return; - - } else if (executor_pid == 0) { - _cleanup_hashmap_free_free_ Hashmap *pids = NULL; - _cleanup_closedir_ DIR *_d = NULL; - struct dirent *de; - - /* We fork this all off from a child process so that - * we can somewhat cleanly make use of SIGALRM to set - * a time limit */ - - reset_all_signal_handlers(); - reset_signal_mask(); - - assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0); - - if (!d) { - d = _d = opendir(directory); - if (!d) { - if (errno == ENOENT) - _exit(EXIT_SUCCESS); - - log_error("Failed to enumerate directory %s: %m", directory); - _exit(EXIT_FAILURE); - } - } - - pids = hashmap_new(NULL); - if (!pids) { - log_oom(); - _exit(EXIT_FAILURE); - } - - FOREACH_DIRENT(de, d, break) { - _cleanup_free_ char *path = NULL; - pid_t pid; - - if (!dirent_is_file(de)) - continue; - - path = strjoin(directory, "/", de->d_name, NULL); - if (!path) { - log_oom(); - _exit(EXIT_FAILURE); - } - - pid = fork(); - if (pid < 0) { - log_error("Failed to fork: %m"); - continue; - } else if (pid == 0) { - char *_argv[2]; - - assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0); - - if (!argv) { - _argv[0] = path; - _argv[1] = NULL; - argv = _argv; - } else - argv[0] = path; - - execv(path, argv); - log_error("Failed to execute %s: %m", path); - _exit(EXIT_FAILURE); - } - - log_debug("Spawned %s as " PID_FMT ".", path, pid); - - r = hashmap_put(pids, UINT_TO_PTR(pid), path); - if (r < 0) { - log_oom(); - _exit(EXIT_FAILURE); - } - - path = NULL; - } - - /* Abort execution of this process after the - * timout. We simply rely on SIGALRM as default action - * terminating the process, and turn on alarm(). */ - - if (timeout != USEC_INFINITY) - alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC); - - while (!hashmap_isempty(pids)) { - _cleanup_free_ char *path = NULL; - pid_t pid; - - pid = PTR_TO_UINT(hashmap_first_key(pids)); - assert(pid > 0); - - path = hashmap_remove(pids, UINT_TO_PTR(pid)); - assert(path); - - wait_for_terminate_and_warn(path, pid); - } - - _exit(EXIT_SUCCESS); - } - - wait_for_terminate_and_warn(directory, executor_pid); -} - -int kill_and_sigcont(pid_t pid, int sig) { - int r; - - r = kill(pid, sig) < 0 ? -errno : 0; - - if (r >= 0) - kill(pid, SIGCONT); - - return r; -} - -bool nulstr_contains(const char*nulstr, const char *needle) { - const char *i; - - if (!nulstr) - return false; - - NULSTR_FOREACH(i, nulstr) - if (streq(i, needle)) - return true; - - return false; -} - -bool plymouth_running(void) { - return access("/run/plymouth/pid", F_OK) >= 0; -} - -char* strshorten(char *s, size_t l) { - assert(s); - - if (l < strlen(s)) - s[l] = 0; - - return s; -} -#endif - -static bool hostname_valid_char(char c) { - return - (c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || - c == '-' || - c == '_' || - c == '.'; -} - -bool hostname_is_valid(const char *s) { - const char *p; - bool dot; - - if (isempty(s)) - return false; - - for (p = s, dot = true; *p; p++) { - if (*p == '.') { - if (dot) - return false; - - dot = true; - } else { - if (!hostname_valid_char(*p)) - return false; - - dot = false; - } - } - - if (dot) - return false; - - if (p-s > HOST_NAME_MAX) - return false; - - return true; -} - -#if 0 /* NM_IGNORED */ -char* hostname_cleanup(char *s, bool lowercase) { - char *p, *d; - bool dot; - - for (p = s, d = s, dot = true; *p; p++) { - if (*p == '.') { - if (dot) - continue; - - *(d++) = '.'; - dot = true; - } else if (hostname_valid_char(*p)) { - *(d++) = lowercase ? tolower(*p) : *p; - dot = false; - } - - } - - if (dot && d > s) - d[-1] = 0; - else - *d = 0; - - strshorten(s, HOST_NAME_MAX); - - return s; -} - -bool machine_name_is_valid(const char *s) { - - if (!hostname_is_valid(s)) - return false; - - /* Machine names should be useful hostnames, but also be - * useful in unit names, hence we enforce a stricter length - * limitation. */ - - if (strlen(s) > 64) - return false; - - return true; -} - -int pipe_eof(int fd) { - struct pollfd pollfd = { - .fd = fd, - .events = POLLIN|POLLHUP, - }; - - int r; - - r = poll(&pollfd, 1, 0); - if (r < 0) - return -errno; - - if (r == 0) - return 0; - - return pollfd.revents & POLLHUP; -} -#endif - -int fd_wait_for_event(int fd, int event, usec_t t) { - - struct pollfd pollfd = { - .fd = fd, - .events = event, - }; - - struct timespec ts; - int r; - - r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); - if (r < 0) - return -errno; - - if (r == 0) - return 0; - - return pollfd.revents; -} - -int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { - FILE *f; - char *t; - int fd; - - assert(path); - assert(_f); - assert(_temp_path); - - t = tempfn_xxxxxx(path); - if (!t) - return -ENOMEM; - - fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC); - if (fd < 0) { - free(t); - return -errno; - } - - f = fdopen(fd, "we"); - if (!f) { - unlink(t); - free(t); - return -errno; - } - - *_f = f; - *_temp_path = t; - - return 0; -} - -#if 0 /* NM_IGNORED */ -int terminal_vhangup_fd(int fd) { - assert(fd >= 0); - - if (ioctl(fd, TIOCVHANGUP) < 0) - return -errno; - - return 0; -} - -int terminal_vhangup(const char *name) { - _cleanup_close_ int fd = -1; - - fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - return terminal_vhangup_fd(fd); -} - -int vt_disallocate(const char *name) { - int fd, r; - unsigned u; - - /* Deallocate the VT if possible. If not possible - * (i.e. because it is the active one), at least clear it - * entirely (including the scrollback buffer) */ - - if (!startswith(name, "/dev/")) - return -EINVAL; - - if (!tty_is_vc(name)) { - /* So this is not a VT. I guess we cannot deallocate - * it then. But let's at least clear the screen */ - - fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - loop_write(fd, - "\033[r" /* clear scrolling region */ - "\033[H" /* move home */ - "\033[2J", /* clear screen */ - 10, false); - safe_close(fd); - - return 0; - } - - if (!startswith(name, "/dev/tty")) - return -EINVAL; - - r = safe_atou(name+8, &u); - if (r < 0) - return r; - - if (u <= 0) - return -EINVAL; - - /* Try to deallocate */ - fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - r = ioctl(fd, VT_DISALLOCATE, u); - safe_close(fd); - - if (r >= 0) - return 0; - - if (errno != EBUSY) - return -errno; - - /* Couldn't deallocate, so let's clear it fully with - * scrollback */ - fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC); - if (fd < 0) - return fd; - - loop_write(fd, - "\033[r" /* clear scrolling region */ - "\033[H" /* move home */ - "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */ - 10, false); - safe_close(fd); - - return 0; -} - -int symlink_atomic(const char *from, const char *to) { - _cleanup_free_ char *t = NULL; - - assert(from); - assert(to); - - t = tempfn_random(to); - if (!t) - return -ENOMEM; - - if (symlink(from, t) < 0) - return -errno; - - if (rename(t, to) < 0) { - unlink_noerrno(t); - return -errno; - } - - return 0; -} - -int mknod_atomic(const char *path, mode_t mode, dev_t dev) { - _cleanup_free_ char *t = NULL; - - assert(path); - - t = tempfn_random(path); - if (!t) - return -ENOMEM; - - if (mknod(t, mode, dev) < 0) - return -errno; - - if (rename(t, path) < 0) { - unlink_noerrno(t); - return -errno; - } - - return 0; -} - -int mkfifo_atomic(const char *path, mode_t mode) { - _cleanup_free_ char *t = NULL; - - assert(path); - - t = tempfn_random(path); - if (!t) - return -ENOMEM; - - if (mkfifo(t, mode) < 0) - return -errno; - - if (rename(t, path) < 0) { - unlink_noerrno(t); - return -errno; - } - - return 0; -} - -bool display_is_local(const char *display) { - assert(display); - - return - display[0] == ':' && - display[1] >= '0' && - display[1] <= '9'; -} - -int socket_from_display(const char *display, char **path) { - size_t k; - char *f, *c; - - assert(display); - assert(path); - - if (!display_is_local(display)) - return -EINVAL; - - k = strspn(display+1, "0123456789"); - - f = new(char, strlen("/tmp/.X11-unix/X") + k + 1); - if (!f) - return -ENOMEM; - - c = stpcpy(f, "/tmp/.X11-unix/X"); - memcpy(c, display+1, k); - c[k] = 0; - - *path = f; - - return 0; -} - -int get_user_creds( - const char **username, - uid_t *uid, gid_t *gid, - const char **home, - const char **shell) { - - struct passwd *p; - uid_t u; - - assert(username); - assert(*username); - - /* We enforce some special rules for uid=0: in order to avoid - * NSS lookups for root we hardcode its data. */ - - if (streq(*username, "root") || streq(*username, "0")) { - *username = "root"; - - if (uid) - *uid = 0; - - if (gid) - *gid = 0; - - if (home) - *home = "/root"; - - if (shell) - *shell = "/bin/sh"; - - return 0; - } - - if (parse_uid(*username, &u) >= 0) { - errno = 0; - p = getpwuid(u); - - /* If there are multiple users with the same id, make - * sure to leave $USER to the configured value instead - * of the first occurrence in the database. However if - * the uid was configured by a numeric uid, then let's - * pick the real username from /etc/passwd. */ - if (p) - *username = p->pw_name; - } else { - errno = 0; - p = getpwnam(*username); - } - - if (!p) - return errno > 0 ? -errno : -ESRCH; - - if (uid) - *uid = p->pw_uid; - - if (gid) - *gid = p->pw_gid; - - if (home) - *home = p->pw_dir; - - if (shell) - *shell = p->pw_shell; - - return 0; -} - -char* uid_to_name(uid_t uid) { - struct passwd *p; - char *r; - - if (uid == 0) - return strdup("root"); - - p = getpwuid(uid); - if (p) - return strdup(p->pw_name); - - if (asprintf(&r, UID_FMT, uid) < 0) - return NULL; - - return r; -} - -char* gid_to_name(gid_t gid) { - struct group *p; - char *r; - - if (gid == 0) - return strdup("root"); - - p = getgrgid(gid); - if (p) - return strdup(p->gr_name); - - if (asprintf(&r, GID_FMT, gid) < 0) - return NULL; - - return r; -} - -int get_group_creds(const char **groupname, gid_t *gid) { - struct group *g; - gid_t id; - - assert(groupname); - - /* We enforce some special rules for gid=0: in order to avoid - * NSS lookups for root we hardcode its data. */ - - if (streq(*groupname, "root") || streq(*groupname, "0")) { - *groupname = "root"; - - if (gid) - *gid = 0; - - return 0; - } - - if (parse_gid(*groupname, &id) >= 0) { - errno = 0; - g = getgrgid(id); - - if (g) - *groupname = g->gr_name; - } else { - errno = 0; - g = getgrnam(*groupname); - } - - if (!g) - return errno > 0 ? -errno : -ESRCH; - - if (gid) - *gid = g->gr_gid; - - return 0; -} - -int in_gid(gid_t gid) { - gid_t *gids; - int ngroups_max, r, i; - - if (getgid() == gid) - return 1; - - if (getegid() == gid) - return 1; - - ngroups_max = sysconf(_SC_NGROUPS_MAX); - assert(ngroups_max > 0); - - gids = alloca(sizeof(gid_t) * ngroups_max); - - r = getgroups(ngroups_max, gids); - if (r < 0) - return -errno; - - for (i = 0; i < r; i++) - if (gids[i] == gid) - return 1; - - return 0; -} - -int in_group(const char *name) { - int r; - gid_t gid; - - r = get_group_creds(&name, &gid); - if (r < 0) - return r; - - return in_gid(gid); -} - -int glob_exists(const char *path) { - _cleanup_globfree_ glob_t g = {}; - int k; - - assert(path); - - errno = 0; - k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); - - if (k == GLOB_NOMATCH) - return 0; - else if (k == GLOB_NOSPACE) - return -ENOMEM; - else if (k == 0) - return !strv_isempty(g.gl_pathv); - else - return errno ? -errno : -EIO; -} - -int glob_extend(char ***strv, const char *path) { - _cleanup_globfree_ glob_t g = {}; - int k; - char **p; - - errno = 0; - k = glob(path, GLOB_NOSORT|GLOB_BRACE, NULL, &g); - - if (k == GLOB_NOMATCH) - return -ENOENT; - else if (k == GLOB_NOSPACE) - return -ENOMEM; - else if (k != 0 || strv_isempty(g.gl_pathv)) - return errno ? -errno : -EIO; - - STRV_FOREACH(p, g.gl_pathv) { - k = strv_extend(strv, *p); - if (k < 0) - break; - } - - return k; -} - -int dirent_ensure_type(DIR *d, struct dirent *de) { - struct stat st; - - assert(d); - assert(de); - - if (de->d_type != DT_UNKNOWN) - return 0; - - if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) - return -errno; - - de->d_type = - S_ISREG(st.st_mode) ? DT_REG : - S_ISDIR(st.st_mode) ? DT_DIR : - S_ISLNK(st.st_mode) ? DT_LNK : - S_ISFIFO(st.st_mode) ? DT_FIFO : - S_ISSOCK(st.st_mode) ? DT_SOCK : - S_ISCHR(st.st_mode) ? DT_CHR : - S_ISBLK(st.st_mode) ? DT_BLK : - DT_UNKNOWN; - - return 0; -} - -int get_files_in_directory(const char *path, char ***list) { - _cleanup_closedir_ DIR *d = NULL; - size_t bufsize = 0, n = 0; - _cleanup_strv_free_ char **l = NULL; - - assert(path); - - /* Returns all files in a directory in *list, and the number - * of files as return value. If list is NULL returns only the - * number. */ - - d = opendir(path); - if (!d) - return -errno; - - for (;;) { - struct dirent *de; - - errno = 0; - de = readdir(d); - if (!de && errno != 0) - return -errno; - if (!de) - break; - - dirent_ensure_type(d, de); - - if (!dirent_is_file(de)) - continue; - - if (list) { - /* one extra slot is needed for the terminating NULL */ - if (!GREEDY_REALLOC(l, bufsize, n + 2)) - return -ENOMEM; - - l[n] = strdup(de->d_name); - if (!l[n]) - return -ENOMEM; - - l[++n] = NULL; - } else - n++; - } - - if (list) { - *list = l; - l = NULL; /* avoid freeing */ - } - - return n; -} -#endif - -char *strjoin(const char *x, ...) { - va_list ap; - size_t l; - char *r, *p; - - va_start(ap, x); - - if (x) { - l = strlen(x); - - for (;;) { - const char *t; - size_t n; - - t = va_arg(ap, const char *); - if (!t) - break; - - n = strlen(t); - if (n > ((size_t) -1) - l) { - va_end(ap); - return NULL; - } - - l += n; - } - } else - l = 0; - - va_end(ap); - - r = new(char, l+1); - if (!r) - return NULL; - - if (x) { - p = stpcpy(r, x); - - va_start(ap, x); - - for (;;) { - const char *t; - - t = va_arg(ap, const char *); - if (!t) - break; - - p = stpcpy(p, t); - } - - va_end(ap); - } else - r[0] = 0; - - return r; -} - -#if 0 /* NM_IGNORED */ -bool is_main_thread(void) { - static thread_local int cached = 0; - - if (_unlikely_(cached == 0)) - cached = getpid() == gettid() ? 1 : -1; - - return cached > 0; -} - -int block_get_whole_disk(dev_t d, dev_t *ret) { - char *p, *s; - int r; - unsigned n, m; - - assert(ret); - - /* If it has a queue this is good enough for us */ - if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0) - return -ENOMEM; - - r = access(p, F_OK); - free(p); - - if (r >= 0) { - *ret = d; - return 0; - } - - /* If it is a partition find the originating device */ - if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0) - return -ENOMEM; - - r = access(p, F_OK); - free(p); - - if (r < 0) - return -ENOENT; - - /* Get parent dev_t */ - if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0) - return -ENOMEM; - - r = read_one_line_file(p, &s); - free(p); - - if (r < 0) - return r; - - r = sscanf(s, "%u:%u", &m, &n); - free(s); - - if (r != 2) - return -EINVAL; - - /* Only return this if it is really good enough for us. */ - if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0) - return -ENOMEM; - - r = access(p, F_OK); - free(p); - - if (r >= 0) { - *ret = makedev(m, n); - return 0; - } - - return -ENOENT; -} - -static const char *const ioprio_class_table[] = { - [IOPRIO_CLASS_NONE] = "none", - [IOPRIO_CLASS_RT] = "realtime", - [IOPRIO_CLASS_BE] = "best-effort", - [IOPRIO_CLASS_IDLE] = "idle" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX); - -static const char *const sigchld_code_table[] = { - [CLD_EXITED] = "exited", - [CLD_KILLED] = "killed", - [CLD_DUMPED] = "dumped", - [CLD_TRAPPED] = "trapped", - [CLD_STOPPED] = "stopped", - [CLD_CONTINUED] = "continued", -}; - -DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int); - -static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = { - [LOG_FAC(LOG_KERN)] = "kern", - [LOG_FAC(LOG_USER)] = "user", - [LOG_FAC(LOG_MAIL)] = "mail", - [LOG_FAC(LOG_DAEMON)] = "daemon", - [LOG_FAC(LOG_AUTH)] = "auth", - [LOG_FAC(LOG_SYSLOG)] = "syslog", - [LOG_FAC(LOG_LPR)] = "lpr", - [LOG_FAC(LOG_NEWS)] = "news", - [LOG_FAC(LOG_UUCP)] = "uucp", - [LOG_FAC(LOG_CRON)] = "cron", - [LOG_FAC(LOG_AUTHPRIV)] = "authpriv", - [LOG_FAC(LOG_FTP)] = "ftp", - [LOG_FAC(LOG_LOCAL0)] = "local0", - [LOG_FAC(LOG_LOCAL1)] = "local1", - [LOG_FAC(LOG_LOCAL2)] = "local2", - [LOG_FAC(LOG_LOCAL3)] = "local3", - [LOG_FAC(LOG_LOCAL4)] = "local4", - [LOG_FAC(LOG_LOCAL5)] = "local5", - [LOG_FAC(LOG_LOCAL6)] = "local6", - [LOG_FAC(LOG_LOCAL7)] = "local7" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0)); - -static const char *const log_level_table[] = { - [LOG_EMERG] = "emerg", - [LOG_ALERT] = "alert", - [LOG_CRIT] = "crit", - [LOG_ERR] = "err", - [LOG_WARNING] = "warning", - [LOG_NOTICE] = "notice", - [LOG_INFO] = "info", - [LOG_DEBUG] = "debug" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG); - -static const char* const sched_policy_table[] = { - [SCHED_OTHER] = "other", - [SCHED_BATCH] = "batch", - [SCHED_IDLE] = "idle", - [SCHED_FIFO] = "fifo", - [SCHED_RR] = "rr" -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX); - -static const char* const rlimit_table[_RLIMIT_MAX] = { - [RLIMIT_CPU] = "LimitCPU", - [RLIMIT_FSIZE] = "LimitFSIZE", - [RLIMIT_DATA] = "LimitDATA", - [RLIMIT_STACK] = "LimitSTACK", - [RLIMIT_CORE] = "LimitCORE", - [RLIMIT_RSS] = "LimitRSS", - [RLIMIT_NOFILE] = "LimitNOFILE", - [RLIMIT_AS] = "LimitAS", - [RLIMIT_NPROC] = "LimitNPROC", - [RLIMIT_MEMLOCK] = "LimitMEMLOCK", - [RLIMIT_LOCKS] = "LimitLOCKS", - [RLIMIT_SIGPENDING] = "LimitSIGPENDING", - [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE", - [RLIMIT_NICE] = "LimitNICE", - [RLIMIT_RTPRIO] = "LimitRTPRIO", - [RLIMIT_RTTIME] = "LimitRTTIME" -}; - -DEFINE_STRING_TABLE_LOOKUP(rlimit, int); - -static const char* const ip_tos_table[] = { - [IPTOS_LOWDELAY] = "low-delay", - [IPTOS_THROUGHPUT] = "throughput", - [IPTOS_RELIABILITY] = "reliability", - [IPTOS_LOWCOST] = "low-cost", -}; - -DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); - -static const char *const __signal_table[] = { - [SIGHUP] = "HUP", - [SIGINT] = "INT", - [SIGQUIT] = "QUIT", - [SIGILL] = "ILL", - [SIGTRAP] = "TRAP", - [SIGABRT] = "ABRT", - [SIGBUS] = "BUS", - [SIGFPE] = "FPE", - [SIGKILL] = "KILL", - [SIGUSR1] = "USR1", - [SIGSEGV] = "SEGV", - [SIGUSR2] = "USR2", - [SIGPIPE] = "PIPE", - [SIGALRM] = "ALRM", - [SIGTERM] = "TERM", -#ifdef SIGSTKFLT - [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */ -#endif - [SIGCHLD] = "CHLD", - [SIGCONT] = "CONT", - [SIGSTOP] = "STOP", - [SIGTSTP] = "TSTP", - [SIGTTIN] = "TTIN", - [SIGTTOU] = "TTOU", - [SIGURG] = "URG", - [SIGXCPU] = "XCPU", - [SIGXFSZ] = "XFSZ", - [SIGVTALRM] = "VTALRM", - [SIGPROF] = "PROF", - [SIGWINCH] = "WINCH", - [SIGIO] = "IO", - [SIGPWR] = "PWR", - [SIGSYS] = "SYS" -}; - -DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int); - -const char *signal_to_string(int signo) { - static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1]; - const char *name; - - name = __signal_to_string(signo); - if (name) - return name; - - if (signo >= SIGRTMIN && signo <= SIGRTMAX) - snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN); - else - snprintf(buf, sizeof(buf), "%d", signo); - - return buf; -} - -int signal_from_string(const char *s) { - int signo; - int offset = 0; - unsigned u; - - signo = __signal_from_string(s); - if (signo > 0) - return signo; - - if (startswith(s, "RTMIN+")) { - s += 6; - offset = SIGRTMIN; - } - if (safe_atou(s, &u) >= 0) { - signo = (int) u + offset; - if (signo > 0 && signo < _NSIG) - return signo; - } - return -EINVAL; -} - -bool kexec_loaded(void) { - bool loaded = false; - char *s; - - if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) { - if (s[0] == '1') - loaded = true; - free(s); - } - return loaded; -} - -int prot_from_flags(int flags) { - - switch (flags & O_ACCMODE) { - - case O_RDONLY: - return PROT_READ; - - case O_WRONLY: - return PROT_WRITE; - - case O_RDWR: - return PROT_READ|PROT_WRITE; - - default: - return -EINVAL; - } -} - -char *format_bytes(char *buf, size_t l, off_t t) { - unsigned i; - - static const struct { - const char *suffix; - off_t factor; - } table[] = { - { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, - { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, - { "G", 1024ULL*1024ULL*1024ULL }, - { "M", 1024ULL*1024ULL }, - { "K", 1024ULL }, - }; - - for (i = 0; i < ELEMENTSOF(table); i++) { - - if (t >= table[i].factor) { - snprintf(buf, l, - "%llu.%llu%s", - (unsigned long long) (t / table[i].factor), - (unsigned long long) (((t*10ULL) / table[i].factor) % 10ULL), - table[i].suffix); - - goto finish; - } - } - - snprintf(buf, l, "%lluB", (unsigned long long) t); - -finish: - buf[l-1] = 0; - return buf; - -} -#endif - -void* memdup(const void *p, size_t l) { - void *r; - - assert(p); - - r = malloc(l); - if (!r) - return NULL; - - memcpy(r, p, l); - return r; -} - -#if 0 /* NM_IGNORED */ -int fd_inc_sndbuf(int fd, size_t n) { - int r, value; - socklen_t l = sizeof(value); - - r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l); - if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) - return 0; - - /* If we have the privileges we will ignore the kernel limit. */ - - value = (int) n; - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0) - if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0) - return -errno; - - return 1; -} - -int fd_inc_rcvbuf(int fd, size_t n) { - int r, value; - socklen_t l = sizeof(value); - - r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l); - if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2) - return 0; - - /* If we have the privileges we will ignore the kernel limit. */ - - value = (int) n; - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0) - if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value)) < 0) - return -errno; - return 1; -} - -int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) { - bool stdout_is_tty, stderr_is_tty; - pid_t parent_pid, agent_pid; - sigset_t ss, saved_ss; - unsigned n, i; - va_list ap; - char **l; - - assert(pid); - assert(path); - - /* Spawns a temporary TTY agent, making sure it goes away when - * we go away */ - - parent_pid = getpid(); - - /* First we temporarily block all signals, so that the new - * child has them blocked initially. This way, we can be sure - * that SIGTERMs are not lost we might send to the agent. */ - assert_se(sigfillset(&ss) >= 0); - assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0); - - agent_pid = fork(); - if (agent_pid < 0) { - assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0); - return -errno; - } - - if (agent_pid != 0) { - assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0); - *pid = agent_pid; - return 0; - } - - /* In the child: - * - * Make sure the agent goes away when the parent dies */ - if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) - _exit(EXIT_FAILURE); - - /* Make sure we actually can kill the agent, if we need to, in - * case somebody invoked us from a shell script that trapped - * SIGTERM or so... */ - reset_all_signal_handlers(); - reset_signal_mask(); - - /* Check whether our parent died before we were able - * to set the death signal and unblock the signals */ - if (getppid() != parent_pid) - _exit(EXIT_SUCCESS); - - /* Don't leak fds to the agent */ - close_all_fds(except, n_except); - - stdout_is_tty = isatty(STDOUT_FILENO); - stderr_is_tty = isatty(STDERR_FILENO); - - if (!stdout_is_tty || !stderr_is_tty) { - int fd; - - /* Detach from stdout/stderr. and reopen - * /dev/tty for them. This is important to - * ensure that when systemctl is started via - * popen() or a similar call that expects to - * read EOF we actually do generate EOF and - * not delay this indefinitely by because we - * keep an unused copy of stdin around. */ - fd = open("/dev/tty", O_WRONLY); - if (fd < 0) { - log_error("Failed to open /dev/tty: %m"); - _exit(EXIT_FAILURE); - } - - if (!stdout_is_tty) - dup2(fd, STDOUT_FILENO); - - if (!stderr_is_tty) - dup2(fd, STDERR_FILENO); - - if (fd > 2) - close(fd); - } - - /* Count arguments */ - va_start(ap, path); - for (n = 0; va_arg(ap, char*); n++) - ; - va_end(ap); - - /* Allocate strv */ - l = alloca(sizeof(char *) * (n + 1)); - - /* Fill in arguments */ - va_start(ap, path); - for (i = 0; i <= n; i++) - l[i] = va_arg(ap, char*); - va_end(ap); - - execv(path, l); - _exit(EXIT_FAILURE); -} - -int setrlimit_closest(int resource, const struct rlimit *rlim) { - struct rlimit highest, fixed; - - assert(rlim); - - if (setrlimit(resource, rlim) >= 0) - return 0; - - if (errno != EPERM) - return -errno; - - /* So we failed to set the desired setrlimit, then let's try - * to get as close as we can */ - assert_se(getrlimit(resource, &highest) == 0); - - fixed.rlim_cur = MIN(rlim->rlim_cur, highest.rlim_max); - fixed.rlim_max = MIN(rlim->rlim_max, highest.rlim_max); - - if (setrlimit(resource, &fixed) < 0) - return -errno; - - return 0; -} - -int getenv_for_pid(pid_t pid, const char *field, char **_value) { - _cleanup_fclose_ FILE *f = NULL; - char *value = NULL; - int r; - bool done = false; - size_t l; - const char *path; - - assert(pid >= 0); - assert(field); - assert(_value); - - path = procfs_file_alloca(pid, "environ"); - - f = fopen(path, "re"); - if (!f) - return -errno; - - l = strlen(field); - r = 0; - - do { - char line[LINE_MAX]; - unsigned i; - - for (i = 0; i < sizeof(line)-1; i++) { - int c; - - c = getc(f); - if (_unlikely_(c == EOF)) { - done = true; - break; - } else if (c == 0) - break; - - line[i] = c; - } - line[i] = 0; - - if (memcmp(line, field, l) == 0 && line[l] == '=') { - value = strdup(line + l + 1); - if (!value) - return -ENOMEM; - - r = 1; - break; - } - - } while (!done); - - *_value = value; - return r; -} - -bool is_valid_documentation_url(const char *url) { - assert(url); - - if (startswith(url, "http://") && url[7]) - return true; - - if (startswith(url, "https://") && url[8]) - return true; - - if (startswith(url, "file:") && url[5]) - return true; - - if (startswith(url, "info:") && url[5]) - return true; - - if (startswith(url, "man:") && url[4]) - return true; - - return false; -} - -bool in_initrd(void) { - static int saved = -1; - struct statfs s; - - if (saved >= 0) - return saved; - - /* We make two checks here: - * - * 1. the flag file /etc/initrd-release must exist - * 2. the root file system must be a memory file system - * - * The second check is extra paranoia, since misdetecting an - * initrd can have bad bad consequences due the initrd - * emptying when transititioning to the main systemd. - */ - - saved = access("/etc/initrd-release", F_OK) >= 0 && - statfs("/", &s) >= 0 && - is_temporary_fs(&s); - - return saved; -} - -void warn_melody(void) { - _cleanup_close_ int fd = -1; - - fd = open("/dev/console", O_WRONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return; - - /* Yeah, this is synchronous. Kinda sucks. But well... */ - - ioctl(fd, KIOCSOUND, (int)(1193180/440)); - usleep(125*USEC_PER_MSEC); - - ioctl(fd, KIOCSOUND, (int)(1193180/220)); - usleep(125*USEC_PER_MSEC); - - ioctl(fd, KIOCSOUND, (int)(1193180/220)); - usleep(125*USEC_PER_MSEC); - - ioctl(fd, KIOCSOUND, 0); -} - -int make_console_stdio(void) { - int fd, r; - - /* Make /dev/console the controlling terminal and stdin/stdout/stderr */ - - fd = acquire_terminal("/dev/console", false, true, true, USEC_INFINITY); - if (fd < 0) { - log_error("Failed to acquire terminal: %s", strerror(-fd)); - return fd; - } - - r = make_stdio(fd); - if (r < 0) { - log_error("Failed to duplicate terminal fd: %s", strerror(-r)); - return r; - } - - return 0; -} - -int get_home_dir(char **_h) { - struct passwd *p; - const char *e; - char *h; - uid_t u; - - assert(_h); - - /* Take the user specified one */ - e = secure_getenv("HOME"); - if (e && path_is_absolute(e)) { - h = strdup(e); - if (!h) - return -ENOMEM; - - *_h = h; - return 0; - } - - /* Hardcode home directory for root to avoid NSS */ - u = getuid(); - if (u == 0) { - h = strdup("/root"); - if (!h) - return -ENOMEM; - - *_h = h; - return 0; - } - - /* Check the database... */ - errno = 0; - p = getpwuid(u); - if (!p) - return errno > 0 ? -errno : -ESRCH; - - if (!path_is_absolute(p->pw_dir)) - return -EINVAL; - - h = strdup(p->pw_dir); - if (!h) - return -ENOMEM; - - *_h = h; - return 0; -} - -int get_shell(char **_s) { - struct passwd *p; - const char *e; - char *s; - uid_t u; - - assert(_s); - - /* Take the user specified one */ - e = getenv("SHELL"); - if (e) { - s = strdup(e); - if (!s) - return -ENOMEM; - - *_s = s; - return 0; - } - - /* Hardcode home directory for root to avoid NSS */ - u = getuid(); - if (u == 0) { - s = strdup("/bin/sh"); - if (!s) - return -ENOMEM; - - *_s = s; - return 0; - } - - /* Check the database... */ - errno = 0; - p = getpwuid(u); - if (!p) - return errno > 0 ? -errno : -ESRCH; - - if (!path_is_absolute(p->pw_shell)) - return -EINVAL; - - s = strdup(p->pw_shell); - if (!s) - return -ENOMEM; - - *_s = s; - return 0; -} - -bool filename_is_safe(const char *p) { - - if (isempty(p)) - return false; - - if (strchr(p, '/')) - return false; - - if (streq(p, ".")) - return false; - - if (streq(p, "..")) - return false; - - if (strlen(p) > FILENAME_MAX) - return false; - - return true; -} - -bool string_is_safe(const char *p) { - const char *t; - - if (!p) - return false; - - for (t = p; *t; t++) { - if (*t > 0 && *t < ' ') - return false; - - if (strchr("\\\"\'\0x7f", *t)) - return false; - } - - return true; -} -#endif - -/** - * Check if a string contains control characters. If 'ok' is non-NULL - * it may be a string containing additional CCs to be considered OK. - */ -bool string_has_cc(const char *p, const char *ok) { - const char *t; - - assert(p); - - for (t = p; *t; t++) { - if (ok && strchr(ok, *t)) - continue; - - if (*t > 0 && *t < ' ') - return true; - - if (*t == 127) - return true; - } - - return false; -} - -#if 0 /* NM_IGNORED */ -bool path_is_safe(const char *p) { - - if (isempty(p)) - return false; - - if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../")) - return false; - - if (strlen(p) > PATH_MAX) - return false; - - /* The following two checks are not really dangerous, but hey, they still are confusing */ - if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./")) - return false; - - if (strstr(p, "//")) - return false; - - return true; -} - -/* hey glibc, APIs with callbacks without a user pointer are so useless */ -void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, - int (*compar) (const void *, const void *, void *), void *arg) { - size_t l, u, idx; - const void *p; - int comparison; - - l = 0; - u = nmemb; - while (l < u) { - idx = (l + u) / 2; - p = (void *)(((const char *) base) + (idx * size)); - comparison = compar(key, p, arg); - if (comparison < 0) - u = idx; - else if (comparison > 0) - l = idx + 1; - else - return (void *)p; - } - return NULL; -} - -bool is_locale_utf8(void) { - const char *set; - static int cached_answer = -1; - - if (cached_answer >= 0) - goto out; - - if (!setlocale(LC_ALL, "")) { - cached_answer = true; - goto out; - } - - set = nl_langinfo(CODESET); - if (!set) { - cached_answer = true; - goto out; - } - - if (streq(set, "UTF-8")) { - cached_answer = true; - goto out; - } - - /* For LC_CTYPE=="C" return true, because CTYPE is effectly - * unset and everything can do to UTF-8 nowadays. */ - set = setlocale(LC_CTYPE, NULL); - if (!set) { - cached_answer = true; - goto out; - } - - /* Check result, but ignore the result if C was set - * explicitly. */ - cached_answer = - streq(set, "C") && - !getenv("LC_ALL") && - !getenv("LC_CTYPE") && - !getenv("LANG"); - -out: - return (bool) cached_answer; -} - -const char *draw_special_char(DrawSpecialChar ch) { - static const char *draw_table[2][_DRAW_SPECIAL_CHAR_MAX] = { - - /* UTF-8 */ { - [DRAW_TREE_VERTICAL] = "\342\224\202 ", /* │ */ - [DRAW_TREE_BRANCH] = "\342\224\234\342\224\200", /* ├─ */ - [DRAW_TREE_RIGHT] = "\342\224\224\342\224\200", /* └─ */ - [DRAW_TREE_SPACE] = " ", /* */ - [DRAW_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */ - [DRAW_BLACK_CIRCLE] = "\342\227\217", /* ● */ - [DRAW_ARROW] = "\342\206\222", /* → */ - [DRAW_DASH] = "\342\200\223", /* – */ - }, - - /* ASCII fallback */ { - [DRAW_TREE_VERTICAL] = "| ", - [DRAW_TREE_BRANCH] = "|-", - [DRAW_TREE_RIGHT] = "`-", - [DRAW_TREE_SPACE] = " ", - [DRAW_TRIANGULAR_BULLET] = ">", - [DRAW_BLACK_CIRCLE] = "*", - [DRAW_ARROW] = "->", - [DRAW_DASH] = "-", - } - }; - - return draw_table[!is_locale_utf8()][ch]; -} - -char *strreplace(const char *text, const char *old_string, const char *new_string) { - const char *f; - char *t, *r; - size_t l, old_len, new_len; - - assert(text); - assert(old_string); - assert(new_string); - - old_len = strlen(old_string); - new_len = strlen(new_string); - - l = strlen(text); - r = new(char, l+1); - if (!r) - return NULL; - - f = text; - t = r; - while (*f) { - char *a; - size_t d, nl; - - if (!startswith(f, old_string)) { - *(t++) = *(f++); - continue; - } - - d = t - r; - nl = l - old_len + new_len; - a = realloc(r, nl + 1); - if (!a) - goto oom; - - l = nl; - r = a; - t = r + d; - - t = stpcpy(t, new_string); - f += old_len; - } - - *t = 0; - return r; - -oom: - free(r); - return NULL; -} - -char *strip_tab_ansi(char **ibuf, size_t *_isz) { - const char *i, *begin = NULL; - enum { - STATE_OTHER, - STATE_ESCAPE, - STATE_BRACKET - } state = STATE_OTHER; - char *obuf = NULL; - size_t osz = 0, isz; - FILE *f; - - assert(ibuf); - assert(*ibuf); - - /* Strips ANSI color and replaces TABs by 8 spaces */ - - isz = _isz ? *_isz : strlen(*ibuf); - - f = open_memstream(&obuf, &osz); - if (!f) - return NULL; - - for (i = *ibuf; i < *ibuf + isz + 1; i++) { - - switch (state) { - - case STATE_OTHER: - if (i >= *ibuf + isz) /* EOT */ - break; - else if (*i == '\x1B') - state = STATE_ESCAPE; - else if (*i == '\t') - fputs(" ", f); - else - fputc(*i, f); - break; - - case STATE_ESCAPE: - if (i >= *ibuf + isz) { /* EOT */ - fputc('\x1B', f); - break; - } else if (*i == '[') { - state = STATE_BRACKET; - begin = i + 1; - } else { - fputc('\x1B', f); - fputc(*i, f); - state = STATE_OTHER; - } - - break; - - case STATE_BRACKET: - - if (i >= *ibuf + isz || /* EOT */ - (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) { - fputc('\x1B', f); - fputc('[', f); - state = STATE_OTHER; - i = begin-1; - } else if (*i == 'm') - state = STATE_OTHER; - break; - } - } - - if (ferror(f)) { - fclose(f); - free(obuf); - return NULL; - } - - fclose(f); - - free(*ibuf); - *ibuf = obuf; - - if (_isz) - *_isz = osz; - - return obuf; -} - -int on_ac_power(void) { - bool found_offline = false, found_online = false; - _cleanup_closedir_ DIR *d = NULL; - - d = opendir("/sys/class/power_supply"); - if (!d) - return -errno; - - for (;;) { - struct dirent *de; - _cleanup_close_ int fd = -1, device = -1; - char contents[6]; - ssize_t n; - - errno = 0; - de = readdir(d); - if (!de && errno != 0) - return -errno; - - if (!de) - break; - - if (ignore_file(de->d_name)) - continue; - - device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (device < 0) { - if (errno == ENOENT || errno == ENOTDIR) - continue; - - return -errno; - } - - fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) { - if (errno == ENOENT) - continue; - - return -errno; - } - - n = read(fd, contents, sizeof(contents)); - if (n < 0) - return -errno; - - if (n != 6 || memcmp(contents, "Mains\n", 6)) - continue; - - safe_close(fd); - fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) { - if (errno == ENOENT) - continue; - - return -errno; - } - - n = read(fd, contents, sizeof(contents)); - if (n < 0) - return -errno; - - if (n != 2 || contents[1] != '\n') - return -EIO; - - if (contents[0] == '1') { - found_online = true; - break; - } else if (contents[0] == '0') - found_offline = true; - else - return -EIO; - } - - return found_online || !found_offline; -} - -static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) { - char **i; - - assert(path); - assert(mode); - assert(_f); - - if (!path_strv_resolve_uniq(search, root)) - return -ENOMEM; - - STRV_FOREACH(i, search) { - _cleanup_free_ char *p = NULL; - FILE *f; - - if (root) - p = strjoin(root, *i, "/", path, NULL); - else - p = strjoin(*i, "/", path, NULL); - if (!p) - return -ENOMEM; - - f = fopen(p, mode); - if (f) { - *_f = f; - return 0; - } - - if (errno != ENOENT) - return -errno; - } - - return -ENOENT; -} - -int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) { - _cleanup_strv_free_ char **copy = NULL; - - assert(path); - assert(mode); - assert(_f); - - if (path_is_absolute(path)) { - FILE *f; - - f = fopen(path, mode); - if (f) { - *_f = f; - return 0; - } - - return -errno; - } - - copy = strv_copy((char**) search); - if (!copy) - return -ENOMEM; - - return search_and_fopen_internal(path, mode, root, copy, _f); -} - -int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) { - _cleanup_strv_free_ char **s = NULL; - - if (path_is_absolute(path)) { - FILE *f; - - f = fopen(path, mode); - if (f) { - *_f = f; - return 0; - } - - return -errno; - } - - s = strv_split_nulstr(search); - if (!s) - return -ENOMEM; - - return search_and_fopen_internal(path, mode, root, s, _f); -} - -char *strextend(char **x, ...) { - va_list ap; - size_t f, l; - char *r, *p; - - assert(x); - - l = f = *x ? strlen(*x) : 0; - - va_start(ap, x); - for (;;) { - const char *t; - size_t n; - - t = va_arg(ap, const char *); - if (!t) - break; - - n = strlen(t); - if (n > ((size_t) -1) - l) { - va_end(ap); - return NULL; - } - - l += n; - } - va_end(ap); - - r = realloc(*x, l+1); - if (!r) - return NULL; - - p = r + f; - - va_start(ap, x); - for (;;) { - const char *t; - - t = va_arg(ap, const char *); - if (!t) - break; - - p = stpcpy(p, t); - } - va_end(ap); - - *p = 0; - *x = r; - - return r + l; -} - -char *strrep(const char *s, unsigned n) { - size_t l; - char *r, *p; - unsigned i; - - assert(s); - - l = strlen(s); - p = r = malloc(l * n + 1); - if (!r) - return NULL; - - for (i = 0; i < n; i++) - p = stpcpy(p, s); - - *p = 0; - return r; -} -#endif - -void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) { - size_t a, newalloc; - void *q; - - assert(p); - assert(allocated); - - if (*allocated >= need) - return *p; - - newalloc = MAX(need * 2, 64u / size); - a = newalloc * size; - - /* check for overflows */ - if (a < size * need) - return NULL; - - q = realloc(*p, a); - if (!q) - return NULL; - - *p = q; - *allocated = newalloc; - return q; -} - -#if 0 /* NM_IGNORED */ -void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) { - size_t prev; - uint8_t *q; - - assert(p); - assert(allocated); - - prev = *allocated; - - q = greedy_realloc(p, allocated, need, size); - if (!q) - return NULL; - - if (*allocated > prev) - memzero(q + prev * size, (*allocated - prev) * size); - - return q; -} - -bool id128_is_valid(const char *s) { - size_t i, l; - - l = strlen(s); - if (l == 32) { - - /* Simple formatted 128bit hex string */ - - for (i = 0; i < l; i++) { - char c = s[i]; - - if (!(c >= '0' && c <= '9') && - !(c >= 'a' && c <= 'z') && - !(c >= 'A' && c <= 'Z')) - return false; - } - - } else if (l == 36) { - - /* Formatted UUID */ - - for (i = 0; i < l; i++) { - char c = s[i]; - - if ((i == 8 || i == 13 || i == 18 || i == 23)) { - if (c != '-') - return false; - } else { - if (!(c >= '0' && c <= '9') && - !(c >= 'a' && c <= 'z') && - !(c >= 'A' && c <= 'Z')) - return false; - } - } - - } else - return false; - - return true; -} - -int split_pair(const char *s, const char *sep, char **l, char **r) { - char *x, *a, *b; - - assert(s); - assert(sep); - assert(l); - assert(r); - - if (isempty(sep)) - return -EINVAL; - - x = strstr(s, sep); - if (!x) - return -EINVAL; - - a = strndup(s, x - s); - if (!a) - return -ENOMEM; - - b = strdup(x + strlen(sep)); - if (!b) { - free(a); - return -ENOMEM; - } - - *l = a; - *r = b; - - return 0; -} - -int shall_restore_state(void) { - _cleanup_free_ char *line = NULL; - const char *p; - int r; - - r = proc_cmdline(&line); - if (r < 0) - return r; - - r = 1; - p = line; - - for (;;) { - _cleanup_free_ char *word = NULL; - const char *e; - int k; - - k = unquote_first_word(&p, &word, true); - if (k < 0) - return k; - if (k == 0) - break; - - e = startswith(word, "systemd.restore_state="); - if (!e) - continue; - - k = parse_boolean(e); - if (k >= 0) - r = k; - } - - return r; -} - -int proc_cmdline(char **ret) { - assert(ret); - - if (detect_container(NULL) > 0) - return get_process_cmdline(1, 0, false, ret); - else - return read_one_line_file("/proc/cmdline", ret); -} - -int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) { - _cleanup_free_ char *line = NULL; - const char *p; - int r; - - assert(parse_item); - - r = proc_cmdline(&line); - if (r < 0) - return r; - - p = line; - for (;;) { - _cleanup_free_ char *word = NULL; - char *value = NULL; - - r = unquote_first_word(&p, &word, true); - if (r < 0) - return r; - if (r == 0) - break; - - /* Filter out arguments that are intended only for the - * initrd */ - if (!in_initrd() && startswith(word, "rd.")) - continue; - - value = strchr(word, '='); - if (value) - *(value++) = 0; - - r = parse_item(word, value); - if (r < 0) - return r; - } - - return 0; -} - -int container_get_leader(const char *machine, pid_t *pid) { - _cleanup_free_ char *s = NULL, *class = NULL; - const char *p; - pid_t leader; - int r; - - assert(machine); - assert(pid); - - p = strappenda("/run/systemd/machines/", machine); - r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL); - if (r == -ENOENT) - return -EHOSTDOWN; - if (r < 0) - return r; - if (!s) - return -EIO; - - if (!streq_ptr(class, "container")) - return -EIO; - - r = parse_pid(s, &leader); - if (r < 0) - return r; - if (leader <= 1) - return -EIO; - - *pid = leader; - return 0; -} - -int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *root_fd) { - _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1; - int rfd = -1; - - assert(pid >= 0); - - if (mntns_fd) { - const char *mntns; - - mntns = procfs_file_alloca(pid, "ns/mnt"); - mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC); - if (mntnsfd < 0) - return -errno; - } - - if (pidns_fd) { - const char *pidns; - - pidns = procfs_file_alloca(pid, "ns/pid"); - pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC); - if (pidnsfd < 0) - return -errno; - } - - if (netns_fd) { - const char *netns; - - netns = procfs_file_alloca(pid, "ns/net"); - netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC); - if (netnsfd < 0) - return -errno; - } - - if (root_fd) { - const char *root; - - root = procfs_file_alloca(pid, "root"); - rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); - if (rfd < 0) - return -errno; - } - - if (pidns_fd) - *pidns_fd = pidnsfd; - - if (mntns_fd) - *mntns_fd = mntnsfd; - - if (netns_fd) - *netns_fd = netnsfd; - - if (root_fd) - *root_fd = rfd; - - pidnsfd = mntnsfd = netnsfd = -1; - - return 0; -} - -int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) { - - if (pidns_fd >= 0) - if (setns(pidns_fd, CLONE_NEWPID) < 0) - return -errno; - - if (mntns_fd >= 0) - if (setns(mntns_fd, CLONE_NEWNS) < 0) - return -errno; - - if (netns_fd >= 0) - if (setns(netns_fd, CLONE_NEWNET) < 0) - return -errno; - - if (root_fd >= 0) { - if (fchdir(root_fd) < 0) - return -errno; - - if (chroot(".") < 0) - return -errno; - } - - if (setresgid(0, 0, 0) < 0) - return -errno; - - if (setgroups(0, NULL) < 0) - return -errno; - - if (setresuid(0, 0, 0) < 0) - return -errno; - - return 0; -} - -bool pid_is_unwaited(pid_t pid) { - /* Checks whether a PID is still valid at all, including a zombie */ - - if (pid <= 0) - return false; - - if (kill(pid, 0) >= 0) - return true; - - return errno != ESRCH; -} - -bool pid_is_alive(pid_t pid) { - int r; - - /* Checks whether a PID is still valid and not a zombie */ - - if (pid <= 0) - return false; - - r = get_process_state(pid); - if (r == -ENOENT || r == 'Z') - return false; - - return true; -} - -int getpeercred(int fd, struct ucred *ucred) { - socklen_t n = sizeof(struct ucred); - struct ucred u; - int r; - - assert(fd >= 0); - assert(ucred); - - r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n); - if (r < 0) - return -errno; - - if (n != sizeof(struct ucred)) - return -EIO; - - /* Check if the data is actually useful and not suppressed due - * to namespacing issues */ - if (u.pid <= 0) - return -ENODATA; - - *ucred = u; - return 0; -} - -int getpeersec(int fd, char **ret) { - socklen_t n = 64; - char *s; - int r; - - assert(fd >= 0); - assert(ret); - - s = new0(char, n); - if (!s) - return -ENOMEM; - - r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); - if (r < 0) { - free(s); - - if (errno != ERANGE) - return -errno; - - s = new0(char, n); - if (!s) - return -ENOMEM; - - r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n); - if (r < 0) { - free(s); - return -errno; - } - } - - if (isempty(s)) { - free(s); - return -ENOTSUP; - } - - *ret = s; - return 0; -} -#endif - -/* This is much like like mkostemp() but is subject to umask(). */ -int mkostemp_safe(char *pattern, int flags) { - _cleanup_umask_ mode_t u; - int fd; - - assert(pattern); - - u = umask(077); - - fd = mkostemp(pattern, flags); - if (fd < 0) - return -errno; - - return fd; -} - -#if 0 /* NM_IGNORED */ -int open_tmpfile(const char *path, int flags) { - char *p; - int fd; - - assert(path); - -#ifdef O_TMPFILE - /* Try O_TMPFILE first, if it is supported */ - fd = open(path, flags|O_TMPFILE, S_IRUSR|S_IWUSR); - if (fd >= 0) - return fd; -#endif - - /* Fall back to unguessable name + unlinking */ - p = strappenda(path, "/systemd-tmp-XXXXXX"); - - fd = mkostemp_safe(p, flags); - if (fd < 0) - return fd; - - unlink(p); - return fd; -} - -int fd_warn_permissions(const char *path, int fd) { - struct stat st; - - if (fstat(fd, &st) < 0) - return -errno; - - if (st.st_mode & 0111) - log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); - - if (st.st_mode & 0002) - log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path); - - if (getpid() == 1 && (st.st_mode & 0044) != 0044) - log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path); - - return 0; -} - -unsigned long personality_from_string(const char *p) { - - /* Parse a personality specifier. We introduce our own - * identifiers that indicate specific ABIs, rather than just - * hints regarding the register size, since we want to keep - * things open for multiple locally supported ABIs for the - * same register size. We try to reuse the ABI identifiers - * used by libseccomp. */ - -#if defined(__x86_64__) - - if (streq(p, "x86")) - return PER_LINUX32; - - if (streq(p, "x86-64")) - return PER_LINUX; - -#elif defined(__i386__) - - if (streq(p, "x86")) - return PER_LINUX; -#endif - - /* personality(7) documents that 0xffffffffUL is used for - * querying the current personality, hence let's use that here - * as error indicator. */ - return 0xffffffffUL; -} - -const char* personality_to_string(unsigned long p) { - -#if defined(__x86_64__) - - if (p == PER_LINUX32) - return "x86"; - - if (p == PER_LINUX) - return "x86-64"; - -#elif defined(__i386__) - - if (p == PER_LINUX) - return "x86"; -#endif - - return NULL; -} - -uint64_t physical_memory(void) { - long mem; - - /* We return this as uint64_t in case we are running as 32bit - * process on a 64bit kernel with huge amounts of memory */ - - mem = sysconf(_SC_PHYS_PAGES); - assert(mem > 0); - - return (uint64_t) mem * (uint64_t) page_size(); -} - -char* mount_test_option(const char *haystack, const char *needle) { - - struct mntent me = { - .mnt_opts = (char*) haystack - }; - - assert(needle); - - /* Like glibc's hasmntopt(), but works on a string, not a - * struct mntent */ - - if (!haystack) - return NULL; - - return hasmntopt(&me, needle); -} - -void hexdump(FILE *f, const void *p, size_t s) { - const uint8_t *b = p; - unsigned n = 0; - - assert(s == 0 || b); - - while (s > 0) { - size_t i; - - fprintf(f, "%04x ", n); - - for (i = 0; i < 16; i++) { - - if (i >= s) - fputs(" ", f); - else - fprintf(f, "%02x ", b[i]); - - if (i == 7) - fputc(' ', f); - } - - fputc(' ', f); - - for (i = 0; i < 16; i++) { - - if (i >= s) - fputc(' ', f); - else - fputc(isprint(b[i]) ? (char) b[i] : '.', f); - } - - fputc('\n', f); - - if (s < 16) - break; - - n += 16; - b += 16; - s -= 16; - } -} - -int update_reboot_param_file(const char *param) { - int r = 0; - - if (param) { - - r = write_string_file(REBOOT_PARAM_FILE, param); - if (r < 0) - log_error("Failed to write reboot param to " - REBOOT_PARAM_FILE": %s", strerror(-r)); - } else - unlink(REBOOT_PARAM_FILE); - - return r; -} - -int umount_recursive(const char *prefix, int flags) { - bool again; - int n = 0, r; - - /* Try to umount everything recursively below a - * directory. Also, take care of stacked mounts, and keep - * unmounting them until they are gone. */ - - do { - _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; - - again = false; - r = 0; - - proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); - if (!proc_self_mountinfo) - return -errno; - - for (;;) { - _cleanup_free_ char *path = NULL, *p = NULL; - int k; - - k = fscanf(proc_self_mountinfo, - "%*s " /* (1) mount id */ - "%*s " /* (2) parent id */ - "%*s " /* (3) major:minor */ - "%*s " /* (4) root */ - "%ms " /* (5) mount point */ - "%*s" /* (6) mount options */ - "%*[^-]" /* (7) optional fields */ - "- " /* (8) separator */ - "%*s " /* (9) file system type */ - "%*s" /* (10) mount source */ - "%*s" /* (11) mount options 2 */ - "%*[^\n]", /* some rubbish at the end */ - &path); - if (k != 1) { - if (k == EOF) - break; - - continue; - } - - p = cunescape(path); - if (!p) - return -ENOMEM; - - if (!path_startswith(p, prefix)) - continue; - - if (umount2(p, flags) < 0) { - r = -errno; - continue; - } - - again = true; - n++; - - break; - } - - } while (again); - - return r ? r : n; -} - -int bind_remount_recursive(const char *prefix, bool ro) { - _cleanup_set_free_free_ Set *done = NULL; - _cleanup_free_ char *cleaned = NULL; - int r; - - /* Recursively remount a directory (and all its submounts) - * read-only or read-write. If the directory is already - * mounted, we reuse the mount and simply mark it - * MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write - * operation). If it isn't we first make it one. Afterwards we - * apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to all - * submounts we can access, too. When mounts are stacked on - * the same mount point we only care for each individual - * "top-level" mount on each point, as we cannot - * influence/access the underlying mounts anyway. We do not - * have any effect on future submounts that might get - * propagated, they migt be writable. This includes future - * submounts that have been triggered via autofs. */ - - cleaned = strdup(prefix); - if (!cleaned) - return -ENOMEM; - - path_kill_slashes(cleaned); - - done = set_new(&string_hash_ops); - if (!done) - return -ENOMEM; - - for (;;) { - _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; - _cleanup_set_free_free_ Set *todo = NULL; - bool top_autofs = false; - char *x; - - todo = set_new(&string_hash_ops); - if (!todo) - return -ENOMEM; - - proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); - if (!proc_self_mountinfo) - return -errno; - - for (;;) { - _cleanup_free_ char *path = NULL, *p = NULL, *type = NULL; - int k; - - k = fscanf(proc_self_mountinfo, - "%*s " /* (1) mount id */ - "%*s " /* (2) parent id */ - "%*s " /* (3) major:minor */ - "%*s " /* (4) root */ - "%ms " /* (5) mount point */ - "%*s" /* (6) mount options (superblock) */ - "%*[^-]" /* (7) optional fields */ - "- " /* (8) separator */ - "%ms " /* (9) file system type */ - "%*s" /* (10) mount source */ - "%*s" /* (11) mount options (bind mount) */ - "%*[^\n]", /* some rubbish at the end */ - &path, - &type); - if (k != 2) { - if (k == EOF) - break; - - continue; - } - - p = cunescape(path); - if (!p) - return -ENOMEM; - - /* Let's ignore autofs mounts. If they aren't - * triggered yet, we want to avoid triggering - * them, as we don't make any guarantees for - * future submounts anyway. If they are - * already triggered, then we will find - * another entry for this. */ - if (streq(type, "autofs")) { - top_autofs = top_autofs || path_equal(cleaned, p); - continue; - } - - if (path_startswith(p, cleaned) && - !set_contains(done, p)) { - - r = set_consume(todo, p); - p = NULL; - - if (r == -EEXIST) - continue; - if (r < 0) - return r; - } - } - - /* If we have no submounts to process anymore and if - * the root is either already done, or an autofs, we - * are done */ - if (set_isempty(todo) && - (top_autofs || set_contains(done, cleaned))) - return 0; - - if (!set_contains(done, cleaned) && - !set_contains(todo, cleaned)) { - /* The prefix directory itself is not yet a - * mount, make it one. */ - if (mount(cleaned, cleaned, NULL, MS_BIND|MS_REC, NULL) < 0) - return -errno; - - if (mount(NULL, prefix, NULL, MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) - return -errno; - - x = strdup(cleaned); - if (!x) - return -ENOMEM; - - r = set_consume(done, x); - if (r < 0) - return r; - } - - while ((x = set_steal_first(todo))) { - - r = set_consume(done, x); - if (r == -EEXIST) - continue; - if (r < 0) - return r; - - if (mount(NULL, x, NULL, MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0) { - - /* Deal with mount points that are - * obstructed by a later mount */ - - if (errno != ENOENT) - return -errno; - } - - } - } -} -#endif - -int fflush_and_check(FILE *f) { - assert(f); - - errno = 0; - fflush(f); - - if (ferror(f)) - return errno ? -errno : -EIO; - - return 0; -} - -char *tempfn_xxxxxx(const char *p) { - const char *fn; - char *t; - size_t k; - - assert(p); - - t = new(char, strlen(p) + 1 + 6 + 1); - if (!t) - return NULL; - - fn = basename(p); - k = fn - p; - - strcpy(stpcpy(stpcpy(mempcpy(t, p, k), "."), fn), "XXXXXX"); - - return t; -} - -#if 0 /* NM_IGNORED */ -char *tempfn_random(const char *p) { - const char *fn; - char *t, *x; - uint64_t u; - size_t k; - unsigned i; - - assert(p); - - t = new(char, strlen(p) + 1 + 16 + 1); - if (!t) - return NULL; - - fn = basename(p); - k = fn - p; - - x = stpcpy(stpcpy(mempcpy(t, p, k), "."), fn); - - u = random_u64(); - for (i = 0; i < 16; i++) { - *(x++) = hexchar(u & 0xF); - u >>= 4; - } - - *x = 0; - - return t; -} -#endif - -/* make sure the hostname is not "localhost" */ -bool is_localhost(const char *hostname) { - assert(hostname); - - /* This tries to identify local host and domain names - * described in RFC6761 plus the redhatism of .localdomain */ - - return streq(hostname, "localhost") || - streq(hostname, "localhost.") || - streq(hostname, "localdomain.") || - streq(hostname, "localdomain") || - endswith(hostname, ".localhost") || - endswith(hostname, ".localhost.") || - endswith(hostname, ".localdomain") || - endswith(hostname, ".localdomain."); -} - -#if 0 /* NM_IGNORED */ -int take_password_lock(const char *root) { - - struct flock flock = { - .l_type = F_WRLCK, - .l_whence = SEEK_SET, - .l_start = 0, - .l_len = 0, - }; - - const char *path; - int fd, r; - - /* This is roughly the same as lckpwdf(), but not as awful. We - * don't want to use alarm() and signals, hence we implement - * our own trivial version of this. - * - * Note that shadow-utils also takes per-database locks in - * addition to lckpwdf(). However, we don't given that they - * are redundant as they they invoke lckpwdf() first and keep - * it during everything they do. The per-database locks are - * awfully racy, and thus we just won't do them. */ - - if (root) - path = strappenda(root, "/etc/.pwd.lock"); - else - path = "/etc/.pwd.lock"; - - fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600); - if (fd < 0) - return -errno; - - r = fcntl(fd, F_SETLKW, &flock); - if (r < 0) { - safe_close(fd); - return -errno; - } - - return fd; -} - -int is_symlink(const char *path) { - struct stat info; - - if (lstat(path, &info) < 0) - return -errno; - - return !!S_ISLNK(info.st_mode); -} - -int is_dir(const char* path, bool follow) { - struct stat st; - int r; - - if (follow) - r = stat(path, &st); - else - r = lstat(path, &st); - if (r < 0) - return -errno; - - return !!S_ISDIR(st.st_mode); -} - -int unquote_first_word(const char **p, char **ret, bool relax) { - _cleanup_free_ char *s = NULL; - size_t allocated = 0, sz = 0; - - enum { - START, - VALUE, - VALUE_ESCAPE, - SINGLE_QUOTE, - SINGLE_QUOTE_ESCAPE, - DOUBLE_QUOTE, - DOUBLE_QUOTE_ESCAPE, - SPACE, - } state = START; - - assert(p); - assert(*p); - assert(ret); - - /* Parses the first word of a string, and returns it in - * *ret. Removes all quotes in the process. When parsing fails - * (because of an uneven number of quotes or similar), leaves - * the pointer *p at the first invalid character. */ - - for (;;) { - char c = **p; - - switch (state) { - - case START: - if (c == 0) - goto finish; - else if (strchr(WHITESPACE, c)) - break; - - state = VALUE; - /* fallthrough */ - - case VALUE: - if (c == 0) - goto finish; - else if (c == '\'') - state = SINGLE_QUOTE; - else if (c == '\\') - state = VALUE_ESCAPE; - else if (c == '\"') - state = DOUBLE_QUOTE; - else if (strchr(WHITESPACE, c)) - state = SPACE; - else { - if (!GREEDY_REALLOC(s, allocated, sz+2)) - return -ENOMEM; - - s[sz++] = c; - } - - break; - - case VALUE_ESCAPE: - if (c == 0) { - if (relax) - goto finish; - return -EINVAL; - } - - if (!GREEDY_REALLOC(s, allocated, sz+2)) - return -ENOMEM; - - s[sz++] = c; - state = VALUE; - - break; - - case SINGLE_QUOTE: - if (c == 0) { - if (relax) - goto finish; - return -EINVAL; - } else if (c == '\'') - state = VALUE; - else if (c == '\\') - state = SINGLE_QUOTE_ESCAPE; - else { - if (!GREEDY_REALLOC(s, allocated, sz+2)) - return -ENOMEM; - - s[sz++] = c; - } - - break; - - case SINGLE_QUOTE_ESCAPE: - if (c == 0) { - if (relax) - goto finish; - return -EINVAL; - } - - if (!GREEDY_REALLOC(s, allocated, sz+2)) - return -ENOMEM; - - s[sz++] = c; - state = SINGLE_QUOTE; - break; - - case DOUBLE_QUOTE: - if (c == 0) - return -EINVAL; - else if (c == '\"') - state = VALUE; - else if (c == '\\') - state = DOUBLE_QUOTE_ESCAPE; - else { - if (!GREEDY_REALLOC(s, allocated, sz+2)) - return -ENOMEM; - - s[sz++] = c; - } - - break; - - case DOUBLE_QUOTE_ESCAPE: - if (c == 0) { - if (relax) - goto finish; - return -EINVAL; - } - - if (!GREEDY_REALLOC(s, allocated, sz+2)) - return -ENOMEM; - - s[sz++] = c; - state = DOUBLE_QUOTE; - break; - - case SPACE: - if (c == 0) - goto finish; - if (!strchr(WHITESPACE, c)) - goto finish; - - break; - } - - (*p) ++; - } - -finish: - if (!s) { - *ret = NULL; - return 0; - } - - s[sz] = 0; - *ret = s; - s = NULL; - - return 1; -} - -int unquote_many_words(const char **p, ...) { - va_list ap; - char **l; - int n = 0, i, c, r; - - /* Parses a number of words from a string, stripping any - * quotes if necessary. */ - - assert(p); - - /* Count how many words are expected */ - va_start(ap, p); - for (;;) { - if (!va_arg(ap, char **)) - break; - n++; - } - va_end(ap); - - if (n <= 0) - return 0; - - /* Read all words into a temporary array */ - l = newa0(char*, n); - for (c = 0; c < n; c++) { - - r = unquote_first_word(p, &l[c], false); - if (r < 0) { - int j; - - for (j = 0; j < c; j++) - free(l[j]); - - return r; - } - - if (r == 0) - break; - } - - /* If we managed to parse all words, return them in the passed - * in parameters */ - va_start(ap, p); - for (i = 0; i < n; i++) { - char **v; - - v = va_arg(ap, char **); - assert(v); - - *v = l[i]; - } - va_end(ap); - - return c; -} - -int free_and_strdup(char **p, const char *s) { - char *t; - - assert(p); - - /* Replaces a string pointer with an strdup()ed new string, - * possibly freeing the old one. */ - - if (s) { - t = strdup(s); - if (!t) - return -ENOMEM; - } else - t = NULL; - - free(*p); - *p = t; - - return 0; -} - -int sethostname_idempotent(const char *s) { - int r; - char buf[HOST_NAME_MAX + 1] = {}; - - assert(s); - - r = gethostname(buf, sizeof(buf)); - if (r < 0) - return -errno; - - if (streq(buf, s)) - return 0; - - r = sethostname(s, strlen(s)); - if (r < 0) - return -errno; - - return 1; -} -#endif - diff --git a/src/dhcp-manager/systemd-dhcp/src/shared/util.h b/src/dhcp-manager/systemd-dhcp/src/shared/util.h deleted file mode 100644 index a7690655..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/shared/util.h +++ /dev/null @@ -1,1038 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#pragma once - -/*** - This file is part of systemd. - - Copyright 2010 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "nm-sd-adapt.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if 0 /* NM_IGNORED */ -#if SIZEOF_PID_T == 4 -# define PID_FMT "%" PRIu32 -#elif SIZEOF_PID_T == 2 -# define PID_FMT "%" PRIu16 -#else -# error Unknown pid_t size -#endif - -#if SIZEOF_UID_T == 4 -# define UID_FMT "%" PRIu32 -#elif SIZEOF_UID_T == 2 -# define UID_FMT "%" PRIu16 -#else -# error Unknown uid_t size -#endif - -#if SIZEOF_GID_T == 4 -# define GID_FMT "%" PRIu32 -#elif SIZEOF_GID_T == 2 -# define GID_FMT "%" PRIu16 -#else -# error Unknown gid_t size -#endif - -#if SIZEOF_TIME_T == 8 -# define PRI_TIME PRIu64 -#elif SIZEOF_TIME_T == 4 -# define PRI_TIME PRIu32 -#else -# error Unknown time_t size -#endif - -#if SIZEOF_RLIM_T == 8 -# define RLIM_FMT "%" PRIu64 -#elif SIZEOF_RLIM_T == 4 -# define RLIM_FMT "%" PRIu32 -#else -# error Unknown rlim_t size -#endif -#endif - -#include "macro.h" -#if 0 /* NM_IGNORED */ -#include "missing.h" -#endif -#include "time-util.h" - -/* What is interpreted as whitespace? */ -#define WHITESPACE " \t\n\r" -#define NEWLINE "\n\r" -#define QUOTES "\"\'" -#define COMMENTS "#;" -#define GLOB_CHARS "*?[" - -/* What characters are special in the shell? */ -/* must be escaped outside and inside double-quotes */ -#define SHELL_NEED_ESCAPE "\"\\`$" -/* can be escaped or double-quoted */ -#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;" - -#define FORMAT_BYTES_MAX 8 - -#define ANSI_HIGHLIGHT_ON "\x1B[1;39m" -#define ANSI_RED_ON "\x1B[31m" -#define ANSI_HIGHLIGHT_RED_ON "\x1B[1;31m" -#define ANSI_GREEN_ON "\x1B[32m" -#define ANSI_HIGHLIGHT_GREEN_ON "\x1B[1;32m" -#define ANSI_HIGHLIGHT_YELLOW_ON "\x1B[1;33m" -#define ANSI_HIGHLIGHT_BLUE_ON "\x1B[1;34m" -#define ANSI_HIGHLIGHT_OFF "\x1B[0m" -#define ANSI_ERASE_TO_END_OF_LINE "\x1B[K" - -size_t page_size(void); -#define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) - -#define streq(a,b) (strcmp((a),(b)) == 0) -#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) -#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) -#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) - -bool streq_ptr(const char *a, const char *b) _pure_; - -#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n))) - -#define new0(t, n) ((t*) calloc((n), sizeof(t))) - -#define newa(t, n) ((t*) alloca(sizeof(t)*(n))) - -#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n))) - -#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) - -#define malloc0(n) (calloc((n), 1)) - -static inline const char* yes_no(bool b) { - return b ? "yes" : "no"; -} - -static inline const char* true_false(bool b) { - return b ? "true" : "false"; -} - -static inline const char* strempty(const char *s) { - return s ? s : ""; -} - -static inline const char* strnull(const char *s) { - return s ? s : "(null)"; -} - -static inline const char *strna(const char *s) { - return s ? s : "n/a"; -} - -static inline bool isempty(const char *p) { - return !p || !p[0]; -} - -static inline char *startswith(const char *s, const char *prefix) { - size_t l; - - l = strlen(prefix); - if (strncmp(s, prefix, l) == 0) - return (char*) s + l; - - return NULL; -} - -static inline char *startswith_no_case(const char *s, const char *prefix) { - size_t l; - - l = strlen(prefix); - if (strncasecmp(s, prefix, l) == 0) - return (char*) s + l; - - return NULL; -} - -char *endswith(const char *s, const char *postfix) _pure_; - -char *first_word(const char *s, const char *word) _pure_; - -int close_nointr(int fd); -int safe_close(int fd); -void safe_close_pair(int p[]); - -void close_many(const int fds[], unsigned n_fd); - -int parse_size(const char *t, off_t base, off_t *size); - -int parse_boolean(const char *v) _pure_; -int parse_pid(const char *s, pid_t* ret_pid); -int parse_uid(const char *s, uid_t* ret_uid); -#define parse_gid(s, ret_uid) parse_uid(s, ret_uid) - -int safe_atou(const char *s, unsigned *ret_u); -int safe_atoi(const char *s, int *ret_i); - -int safe_atollu(const char *s, unsigned long long *ret_u); -int safe_atolli(const char *s, long long int *ret_i); - -int safe_atod(const char *s, double *ret_d); - -int safe_atou8(const char *s, uint8_t *ret); - -#if LONG_MAX == INT_MAX -static inline int safe_atolu(const char *s, unsigned long *ret_u) { - assert_cc(sizeof(unsigned long) == sizeof(unsigned)); - return safe_atou(s, (unsigned*) ret_u); -} -static inline int safe_atoli(const char *s, long int *ret_u) { - assert_cc(sizeof(long int) == sizeof(int)); - return safe_atoi(s, (int*) ret_u); -} -#else -static inline int safe_atolu(const char *s, unsigned long *ret_u) { - assert_cc(sizeof(unsigned long) == sizeof(unsigned long long)); - return safe_atollu(s, (unsigned long long*) ret_u); -} -static inline int safe_atoli(const char *s, long int *ret_u) { - assert_cc(sizeof(long int) == sizeof(long long int)); - return safe_atolli(s, (long long int*) ret_u); -} -#endif - -static inline int safe_atou32(const char *s, uint32_t *ret_u) { - assert_cc(sizeof(uint32_t) == sizeof(unsigned)); - return safe_atou(s, (unsigned*) ret_u); -} - -static inline int safe_atoi32(const char *s, int32_t *ret_i) { - assert_cc(sizeof(int32_t) == sizeof(int)); - return safe_atoi(s, (int*) ret_i); -} - -static inline int safe_atou64(const char *s, uint64_t *ret_u) { - assert_cc(sizeof(uint64_t) == sizeof(unsigned long long)); - return safe_atollu(s, (unsigned long long*) ret_u); -} - -static inline int safe_atoi64(const char *s, int64_t *ret_i) { - assert_cc(sizeof(int64_t) == sizeof(long long int)); - return safe_atolli(s, (long long int*) ret_i); -} - -int safe_atou16(const char *s, uint16_t *ret); -int safe_atoi16(const char *s, int16_t *ret); - -const char* split(const char **state, size_t *l, const char *separator, bool quoted); - -#define FOREACH_WORD(word, length, s, state) \ - _FOREACH_WORD(word, length, s, WHITESPACE, false, state) - -#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ - _FOREACH_WORD(word, length, s, separator, false, state) - -#define FOREACH_WORD_QUOTED(word, length, s, state) \ - _FOREACH_WORD(word, length, s, WHITESPACE, true, state) - -#define _FOREACH_WORD(word, length, s, separator, quoted, state) \ - for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted))) - -pid_t get_parent_of_pid(pid_t pid, pid_t *ppid); -int get_starttime_of_pid(pid_t pid, unsigned long long *st); - -char *strappend(const char *s, const char *suffix); -char *strnappend(const char *s, const char *suffix, size_t length); - -char *replace_env(const char *format, char **env); -char **replace_env_argv(char **argv, char **env); - -int readlinkat_malloc(int fd, const char *p, char **ret); -int readlink_malloc(const char *p, char **r); -int readlink_value(const char *p, char **ret); -int readlink_and_make_absolute(const char *p, char **r); -int readlink_and_canonicalize(const char *p, char **r); - -int reset_all_signal_handlers(void); -int reset_signal_mask(void); - -char *strstrip(char *s); -char *delete_chars(char *s, const char *bad); -char *truncate_nl(char *s); - -char *file_in_same_dir(const char *path, const char *filename); - -int rmdir_parents(const char *path, const char *stop); - -int get_process_state(pid_t pid); -int get_process_comm(pid_t pid, char **name); -int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line); -int get_process_exe(pid_t pid, char **name); -int get_process_uid(pid_t pid, uid_t *uid); -int get_process_gid(pid_t pid, gid_t *gid); -int get_process_capeff(pid_t pid, char **capeff); - -char hexchar(int x) _const_; -int unhexchar(char c) _const_; -char octchar(int x) _const_; -int unoctchar(char c) _const_; -char decchar(int x) _const_; -int undecchar(char c) _const_; - -char *cescape(const char *s); -char *cunescape(const char *s); -char *cunescape_length(const char *s, size_t length); -char *cunescape_length_with_prefix(const char *s, size_t length, const char *prefix); - -char *xescape(const char *s, const char *bad); - -char *ascii_strlower(char *path); - -bool dirent_is_file(const struct dirent *de) _pure_; -bool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) _pure_; - -bool ignore_file(const char *filename) _pure_; - -bool chars_intersect(const char *a, const char *b) _pure_; - -int make_stdio(int fd); -int make_null_stdio(void); -int make_console_stdio(void); - -int dev_urandom(void *p, size_t n); -void random_bytes(void *p, size_t n); -void initialize_srand(void); - -static inline uint64_t random_u64(void) { - uint64_t u; - random_bytes(&u, sizeof(u)); - return u; -} - -static inline uint32_t random_u32(void) { - uint32_t u; - random_bytes(&u, sizeof(u)); - return u; -} - -/* For basic lookup tables with strictly enumerated entries */ -#define __DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ - scope const char *name##_to_string(type i) { \ - if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \ - return NULL; \ - return name##_table[i]; \ - } \ - scope type name##_from_string(const char *s) { \ - type i; \ - if (!s) \ - return (type) -1; \ - for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \ - if (name##_table[i] && \ - streq(name##_table[i], s)) \ - return i; \ - return (type) -1; \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ - -#define DEFINE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,) -#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,static) - -/* For string conversions where numbers are also acceptable */ -#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ - int name##_to_string_alloc(type i, char **str) { \ - char *s; \ - int r; \ - if (i < 0 || i > max) \ - return -ERANGE; \ - if (i < (type) ELEMENTSOF(name##_table)) { \ - s = strdup(name##_table[i]); \ - if (!s) \ - return log_oom(); \ - } else { \ - r = asprintf(&s, "%u", i); \ - if (r < 0) \ - return log_oom(); \ - } \ - *str = s; \ - return 0; \ - } \ - type name##_from_string(const char *s) { \ - type i; \ - unsigned u = 0; \ - assert(s); \ - for (i = 0; i < (type)ELEMENTSOF(name##_table); i++) \ - if (name##_table[i] && \ - streq(name##_table[i], s)) \ - return i; \ - if (safe_atou(s, &u) >= 0 && u <= max) \ - return (type) u; \ - return (type) -1; \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ - -int fd_nonblock(int fd, bool nonblock); -int fd_cloexec(int fd, bool cloexec); - -int close_all_fds(const int except[], unsigned n_except); - -bool fstype_is_network(const char *fstype); - -int chvt(int vt); - -int read_one_char(FILE *f, char *ret, usec_t timeout, bool *need_nl); -int ask_char(char *ret, const char *replies, const char *text, ...) _printf_(3, 4); -int ask_string(char **ret, const char *text, ...) _printf_(2, 3); - -int reset_terminal_fd(int fd, bool switch_to_text); -int reset_terminal(const char *name); - -int open_terminal(const char *name, int mode); -int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm, usec_t timeout); -int release_terminal(void); - -int flush_fd(int fd); - -int ignore_signals(int sig, ...); -int default_signals(int sig, ...); -int sigaction_many(const struct sigaction *sa, ...); - -int fopen_temporary(const char *path, FILE **_f, char **_temp_path); - -ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll); -ssize_t loop_write(int fd, const void *buf, size_t nbytes, bool do_poll); - -bool is_device_path(const char *path); - -int dir_is_empty(const char *path); -char* dirname_malloc(const char *path); - -void rename_process(const char name[8]); - -void sigset_add_many(sigset_t *ss, ...); -int sigprocmask_many(int how, ...); - -bool hostname_is_set(void); - -char* lookup_uid(uid_t uid); -char* gethostname_malloc(void); -char* getlogname_malloc(void); -char* getusername_malloc(void); - -int getttyname_malloc(int fd, char **r); -int getttyname_harder(int fd, char **r); - -int get_ctty_devnr(pid_t pid, dev_t *d); -int get_ctty(pid_t, dev_t *_devnr, char **r); - -int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); -int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid); - -int rm_rf_children(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev); -int rm_rf_children_dangerous(int fd, bool only_dirs, bool honour_sticky, struct stat *root_dev); -int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky); -int rm_rf_dangerous(const char *path, bool only_dirs, bool delete_root, bool honour_sticky); - -int pipe_eof(int fd); - -cpu_set_t* cpu_set_malloc(unsigned *ncpus); - -int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0); -int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5); - -int fd_columns(int fd); -unsigned columns(void); -int fd_lines(int fd); -unsigned lines(void); -void columns_lines_cache_reset(int _unused_ signum); - -bool on_tty(void); - -static inline const char *ansi_highlight(void) { - return on_tty() ? ANSI_HIGHLIGHT_ON : ""; -} - -static inline const char *ansi_highlight_red(void) { - return on_tty() ? ANSI_HIGHLIGHT_RED_ON : ""; -} - -static inline const char *ansi_highlight_green(void) { - return on_tty() ? ANSI_HIGHLIGHT_GREEN_ON : ""; -} - -static inline const char *ansi_highlight_yellow(void) { - return on_tty() ? ANSI_HIGHLIGHT_YELLOW_ON : ""; -} - -static inline const char *ansi_highlight_blue(void) { - return on_tty() ? ANSI_HIGHLIGHT_BLUE_ON : ""; -} - -static inline const char *ansi_highlight_off(void) { - return on_tty() ? ANSI_HIGHLIGHT_OFF : ""; -} - -int files_same(const char *filea, const char *fileb); - -int running_in_chroot(void); - -char *ellipsize(const char *s, size_t length, unsigned percent); - /* bytes columns */ -char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent); - -int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode); -int touch(const char *path); - -char *unquote(const char *s, const char *quotes); -char *normalize_env_assignment(const char *s); - -int wait_for_terminate(pid_t pid, siginfo_t *status); -int wait_for_terminate_and_warn(const char *name, pid_t pid); - -noreturn void freeze(void); - -bool null_or_empty(struct stat *st) _pure_; -int null_or_empty_path(const char *fn); -int null_or_empty_fd(int fd); - -DIR *xopendirat(int dirfd, const char *name, int flags); - -char *fstab_node_to_udev_node(const char *p); - -char *resolve_dev_console(char **active); -bool tty_is_vc(const char *tty); -bool tty_is_vc_resolve(const char *tty); -bool tty_is_console(const char *tty) _pure_; -int vtnr_from_tty(const char *tty); -const char *default_term_for_tty(const char *tty); - -void execute_directory(const char *directory, DIR *_d, usec_t timeout, char *argv[]); - -int kill_and_sigcont(pid_t pid, int sig); - -bool nulstr_contains(const char*nulstr, const char *needle); - -bool plymouth_running(void); - -bool hostname_is_valid(const char *s) _pure_; -char* hostname_cleanup(char *s, bool lowercase); - -bool machine_name_is_valid(const char *s) _pure_; - -char* strshorten(char *s, size_t l); - -int terminal_vhangup_fd(int fd); -int terminal_vhangup(const char *name); - -int vt_disallocate(const char *name); - -int symlink_atomic(const char *from, const char *to); -int mknod_atomic(const char *path, mode_t mode, dev_t dev); -int mkfifo_atomic(const char *path, mode_t mode); - -int fchmod_umask(int fd, mode_t mode); - -bool display_is_local(const char *display) _pure_; -int socket_from_display(const char *display, char **path); - -int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell); -int get_group_creds(const char **groupname, gid_t *gid); - -int in_gid(gid_t gid); -int in_group(const char *name); - -char* uid_to_name(uid_t uid); -char* gid_to_name(gid_t gid); - -int glob_exists(const char *path); -int glob_extend(char ***strv, const char *path); - -int dirent_ensure_type(DIR *d, struct dirent *de); - -int get_files_in_directory(const char *path, char ***list); - -char *strjoin(const char *x, ...) _sentinel_; - -bool is_main_thread(void); - -static inline bool _pure_ in_charset(const char *s, const char* charset) { - assert(s); - assert(charset); - return s[strspn(s, charset)] == '\0'; -} - -int block_get_whole_disk(dev_t d, dev_t *ret); - -#define NULSTR_FOREACH(i, l) \ - for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) - -#define NULSTR_FOREACH_PAIR(i, j, l) \ - for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i)) - -int ioprio_class_to_string_alloc(int i, char **s); -int ioprio_class_from_string(const char *s); - -const char *sigchld_code_to_string(int i) _const_; -int sigchld_code_from_string(const char *s) _pure_; - -int log_facility_unshifted_to_string_alloc(int i, char **s); -int log_facility_unshifted_from_string(const char *s); - -int log_level_to_string_alloc(int i, char **s); -int log_level_from_string(const char *s); - -int sched_policy_to_string_alloc(int i, char **s); -int sched_policy_from_string(const char *s); - -const char *rlimit_to_string(int i) _const_; -int rlimit_from_string(const char *s) _pure_; - -int ip_tos_to_string_alloc(int i, char **s); -int ip_tos_from_string(const char *s); - -const char *signal_to_string(int i) _const_; -int signal_from_string(const char *s) _pure_; - -int signal_from_string_try_harder(const char *s); - -extern int saved_argc; -extern char **saved_argv; - -bool kexec_loaded(void); - -int prot_from_flags(int flags) _const_; - -char *format_bytes(char *buf, size_t l, off_t t); - -int fd_wait_for_event(int fd, int event, usec_t timeout); - -void* memdup(const void *p, size_t l) _alloc_(2); - -int is_kernel_thread(pid_t pid); - -int fd_inc_sndbuf(int fd, size_t n); -int fd_inc_rcvbuf(int fd, size_t n); - -int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...); - -int setrlimit_closest(int resource, const struct rlimit *rlim); - -int getenv_for_pid(pid_t pid, const char *field, char **_value); - -bool is_valid_documentation_url(const char *url) _pure_; - -bool in_initrd(void); - -void warn_melody(void); - -int get_home_dir(char **ret); -int get_shell(char **_ret); - -static inline void freep(void *p) { - free(*(void**) p); -} - -#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ - static inline void func##p(type *p) { \ - if (*p) \ - func(*p); \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ - -static inline void closep(int *fd) { - safe_close(*fd); -} - -static inline void umaskp(mode_t *u) { - umask(*u); -} - -static inline void close_pairp(int (*p)[2]) { - safe_close_pair(*p); -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, fclose); -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); -DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); - -#define _cleanup_free_ _cleanup_(freep) -#define _cleanup_close_ _cleanup_(closep) -#define _cleanup_umask_ _cleanup_(umaskp) -#define _cleanup_globfree_ _cleanup_(globfree) -#define _cleanup_fclose_ _cleanup_(fclosep) -#define _cleanup_pclose_ _cleanup_(pclosep) -#define _cleanup_closedir_ _cleanup_(closedirp) -#define _cleanup_endmntent_ _cleanup_(endmntentp) -#define _cleanup_close_pair_ _cleanup_(close_pairp) - -_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) - return NULL; - - return malloc(a * b); -} - -_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) - return NULL; - - return realloc(p, a * b); -} - -_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) { - if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) - return NULL; - - return memdup(p, a * b); -} - -bool filename_is_safe(const char *p) _pure_; -bool path_is_safe(const char *p) _pure_; -bool string_is_safe(const char *p) _pure_; -bool string_has_cc(const char *p, const char *ok) _pure_; - -/** - * Check if a string contains any glob patterns. - */ -_pure_ static inline bool string_is_glob(const char *p) { - return !!strpbrk(p, GLOB_CHARS); -} - -void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, - int (*compar) (const void *, const void *, void *), - void *arg); - -bool is_locale_utf8(void); - -typedef enum DrawSpecialChar { - DRAW_TREE_VERTICAL, - DRAW_TREE_BRANCH, - DRAW_TREE_RIGHT, - DRAW_TREE_SPACE, - DRAW_TRIANGULAR_BULLET, - DRAW_BLACK_CIRCLE, - DRAW_ARROW, - DRAW_DASH, - _DRAW_SPECIAL_CHAR_MAX -} DrawSpecialChar; - -const char *draw_special_char(DrawSpecialChar ch); - -char *strreplace(const char *text, const char *old_string, const char *new_string); - -char *strip_tab_ansi(char **p, size_t *l); - -int on_ac_power(void); - -int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f); -int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f); - -#define FOREACH_LINE(line, f, on_error) \ - for (;;) \ - if (!fgets(line, sizeof(line), f)) { \ - if (ferror(f)) { \ - on_error; \ - } \ - break; \ - } else - -#define FOREACH_DIRENT(de, d, on_error) \ - for (errno = 0, de = readdir(d);; errno = 0, de = readdir(d)) \ - if (!de) { \ - if (errno > 0) { \ - on_error; \ - } \ - break; \ - } else if (ignore_file((de)->d_name)) \ - continue; \ - else - -static inline void *mempset(void *s, int c, size_t n) { - memset(s, c, n); - return (uint8_t*)s + n; -} - -char *hexmem(const void *p, size_t l); -void *unhexmem(const char *p, size_t l); - -char *strextend(char **x, ...) _sentinel_; -char *strrep(const char *s, unsigned n); - -void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); -void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); -#define GREEDY_REALLOC(array, allocated, need) \ - greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) - -#define GREEDY_REALLOC0(array, allocated, need) \ - greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0])) - -static inline void _reset_errno_(int *saved_errno) { - errno = *saved_errno; -} - -#define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno - -static inline int negative_errno(void) { - /* This helper should be used to shut up gcc if you know 'errno' is - * negative. Instead of "return -errno;", use "return negative_errno();" - * It will suppress bogus gcc warnings in case it assumes 'errno' might - * be 0 and thus the caller's error-handling might not be triggered. */ - assert_return(errno > 0, -EINVAL); - return -errno; -} - -struct _umask_struct_ { - mode_t mask; - bool quit; -}; - -static inline void _reset_umask_(struct _umask_struct_ *s) { - umask(s->mask); -}; - -#define RUN_WITH_UMASK(mask) \ - for (_cleanup_(_reset_umask_) struct _umask_struct_ _saved_umask_ = { umask(mask), false }; \ - !_saved_umask_.quit ; \ - _saved_umask_.quit = true) - -static inline unsigned u64log2(uint64_t n) { -#if __SIZEOF_LONG_LONG__ == 8 - return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0; -#else -#error "Wut?" -#endif -} - -static inline unsigned u32ctz(uint32_t n) { -#if __SIZEOF_INT__ == 4 - return __builtin_ctz(n); -#else -#error "Wut?" -#endif -} - -static inline int log2i(int x) { - assert(x > 0); - - return __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1; -} - -static inline unsigned log2u(unsigned x) { - assert(x > 0); - - return sizeof(unsigned) * 8 - __builtin_clz(x) - 1; -} - -static inline unsigned log2u_round_up(unsigned x) { - assert(x > 0); - - if (x == 1) - return 0; - - return log2u(x - 1) + 1; -} - -static inline bool logind_running(void) { - return access("/run/systemd/seats/", F_OK) >= 0; -} - -#define DECIMAL_STR_WIDTH(x) \ - ({ \ - typeof(x) _x_ = (x); \ - unsigned ans = 1; \ - while (_x_ /= 10) \ - ans++; \ - ans; \ - }) - -int unlink_noerrno(const char *path); - -#define alloca0(n) \ - ({ \ - char *_new_; \ - size_t _len_ = n; \ - _new_ = alloca(_len_); \ - (void *) memset(_new_, 0, _len_); \ - }) - -#define alloca_align(size, align) \ - ({ \ - void *_ptr_; \ - size_t _mask_ = (align) - 1; \ - _ptr_ = alloca((size) + _mask_); \ - (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ - }) - -#define alloca0_align(size, align) \ - ({ \ - void *_new_; \ - size_t _size_ = (size); \ - _new_ = alloca_align(_size_, (align)); \ - (void*)memset(_new_, 0, _size_); \ - }) - -#define strappenda(a, ...) \ - ({ \ - int _len = strlen(a); \ - unsigned _i; \ - char *_d_, *_p_; \ - const char *_appendees_[] = { __VA_ARGS__ }; \ - for (_i = 0; _i < ELEMENTSOF(_appendees_); _i++) \ - _len += strlen(_appendees_[_i]); \ - _d_ = alloca(_len + 1); \ - _p_ = stpcpy(_d_, a); \ - for (_i = 0; _i < ELEMENTSOF(_appendees_); _i++) \ - _p_ = stpcpy(_p_, _appendees_[_i]); \ - _d_; \ - }) - -#define procfs_file_alloca(pid, field) \ - ({ \ - pid_t _pid_ = (pid); \ - const char *_r_; \ - if (_pid_ == 0) { \ - _r_ = ("/proc/self/" field); \ - } else { \ - _r_ = alloca(strlen("/proc/") + DECIMAL_STR_MAX(pid_t) + 1 + sizeof(field)); \ - sprintf((char*) _r_, "/proc/"PID_FMT"/" field, _pid_); \ - } \ - _r_; \ - }) - -struct _locale_struct_ { - locale_t saved_locale; - locale_t new_locale; - bool quit; -}; - -static inline void _reset_locale_(struct _locale_struct_ *s) { - PROTECT_ERRNO; - if (s->saved_locale != (locale_t) 0) - uselocale(s->saved_locale); - if (s->new_locale != (locale_t) 0) - freelocale(s->new_locale); -} - -#define RUN_WITH_LOCALE(mask, loc) \ - for (_cleanup_(_reset_locale_) struct _locale_struct_ _saved_locale_ = { (locale_t) 0, (locale_t) 0, false }; \ - ({ \ - if (!_saved_locale_.quit) { \ - PROTECT_ERRNO; \ - _saved_locale_.new_locale = newlocale((mask), (loc), (locale_t) 0); \ - if (_saved_locale_.new_locale != (locale_t) 0) \ - _saved_locale_.saved_locale = uselocale(_saved_locale_.new_locale); \ - } \ - !_saved_locale_.quit; }) ; \ - _saved_locale_.quit = true) - -bool id128_is_valid(const char *s) _pure_; - -int split_pair(const char *s, const char *sep, char **l, char **r); - -int shall_restore_state(void); - -/** - * Normal qsort requires base to be nonnull. Here were require - * that only if nmemb > 0. - */ -static inline void qsort_safe(void *base, size_t nmemb, size_t size, - int (*compar)(const void *, const void *)) { - if (nmemb) { - assert(base); - qsort(base, nmemb, size, compar); - } -} - -int proc_cmdline(char **ret); -int parse_proc_cmdline(int (*parse_word)(const char *key, const char *value)); - -int container_get_leader(const char *machine, pid_t *pid); - -int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *root_fd); -int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd); - -bool pid_is_alive(pid_t pid); -bool pid_is_unwaited(pid_t pid); - -#if 0 /* NM_IGNORED */ -int getpeercred(int fd, struct ucred *ucred); -int getpeersec(int fd, char **ret); -#endif - -int writev_safe(int fd, const struct iovec *w, int j); - -int mkostemp_safe(char *pattern, int flags); -int open_tmpfile(const char *path, int flags); - -int fd_warn_permissions(const char *path, int fd); - -unsigned long personality_from_string(const char *p); -const char *personality_to_string(unsigned long); - -uint64_t physical_memory(void); - -char* mount_test_option(const char *haystack, const char *needle); - -void hexdump(FILE *f, const void *p, size_t s); - -#if 0 /* NM_IGNORED */ -union file_handle_union { - struct file_handle handle; - char padding[sizeof(struct file_handle) + MAX_HANDLE_SZ]; -}; -#endif - -int update_reboot_param_file(const char *param); - -int umount_recursive(const char *target, int flags); - -int bind_remount_recursive(const char *prefix, bool ro); - -int fflush_and_check(FILE *f); - -char *tempfn_xxxxxx(const char *p); -char *tempfn_random(const char *p); - -bool is_localhost(const char *hostname); - -int take_password_lock(const char *root); - -int is_symlink(const char *path); -int is_dir(const char *path, bool follow); - -int unquote_first_word(const char **p, char **ret, bool relax); -int unquote_many_words(const char **p, ...) _sentinel_; - -int free_and_strdup(char **p, const char *s); - -int sethostname_idempotent(const char *s); diff --git a/src/dhcp-manager/systemd-dhcp/src/systemd/_sd-common.h b/src/dhcp-manager/systemd-dhcp/src/systemd/_sd-common.h deleted file mode 100644 index 896a027e..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/systemd/_sd-common.h +++ /dev/null @@ -1,78 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosdcommonhfoo -#define foosdcommonhfoo - -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -/* This is a private header; never even think of including this directly! */ - -#if __INCLUDE_LEVEL__ <= 1 -#error "Do not include _sd-common.h directly; it is a private header." -#endif - -#ifndef _sd_printf_ -# if __GNUC__ >= 4 -# define _sd_printf_(a,b) __attribute__ ((format (printf, a, b))) -# else -# define _sd_printf_(a,b) -# endif -#endif - -#ifndef _sd_sentinel_ -# define _sd_sentinel_ __attribute__((sentinel)) -#endif - -#ifndef _sd_packed_ -# define _sd_packed_ __attribute__((packed)) -#endif - -#ifndef _sd_pure_ -# define _sd_pure_ __attribute__((pure)) -#endif - -#ifndef _SD_STRINGIFY -# define _SD_XSTRINGIFY(x) #x -# define _SD_STRINGIFY(x) _SD_XSTRINGIFY(x) -#endif - -#ifndef _SD_BEGIN_DECLARATIONS -# ifdef __cplusplus -# define _SD_BEGIN_DECLARATIONS \ - extern "C" { \ - struct __useless_struct_to_allow_trailing_semicolon__ -# else -# define _SD_BEGIN_DECLARATIONS \ - struct __useless_struct_to_allow_trailing_semicolon__ -# endif -#endif - -#ifndef _SD_END_DECLARATIONS -# ifdef __cplusplus -# define _SD_END_DECLARATIONS \ - } \ - struct __useless_struct_to_allow_trailing_semicolon__ -# else -# define _SD_END_DECLARATIONS \ - struct __useless_struct_to_allow_trailing_semicolon__ -# endif -#endif - -#endif diff --git a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-client.h b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-client.h deleted file mode 100644 index 951662e5..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-client.h +++ /dev/null @@ -1,75 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosddhcpclienthfoo -#define foosddhcpclienthfoo - -/*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "sd-event.h" -#include "sd-dhcp-lease.h" - -enum { - DHCP_EVENT_STOP = 0, - DHCP_EVENT_IP_ACQUIRE = 1, - DHCP_EVENT_IP_CHANGE = 2, - DHCP_EVENT_EXPIRED = 3, - DHCP_EVENT_RENEW = 4, -}; - -typedef struct sd_dhcp_client sd_dhcp_client; - -typedef void (*sd_dhcp_client_cb_t)(sd_dhcp_client *client, int event, - void *userdata); -int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb, - void *userdata); - - -int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option); -int sd_dhcp_client_set_request_address(sd_dhcp_client *client, - const struct in_addr *last_address); -int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast); -int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index); -int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, - size_t addr_len, uint16_t arp_type); -int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, - const uint8_t *data, size_t data_len); -int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, - const uint8_t **data, size_t *data_len); -int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu); -int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname); -int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, const char *vci); -int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret); - -int sd_dhcp_client_stop(sd_dhcp_client *client); -int sd_dhcp_client_start(sd_dhcp_client *client); - -sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client); -sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client); - -int sd_dhcp_client_new(sd_dhcp_client **ret); - -int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int priority); -int sd_dhcp_client_detach_event(sd_dhcp_client *client); -sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client); - -#endif diff --git a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-lease.h b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-lease.h deleted file mode 100644 index 079a1bb3..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp-lease.h +++ /dev/null @@ -1,55 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosddhcpleasehfoo -#define foosddhcpleasehfoo - -/*** - This file is part of systemd. - - Copyright (C) 2013 Intel Corporation. All rights reserved. - Copyright (C) 2014 Tom Gundersen - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include - -typedef struct sd_dhcp_lease sd_dhcp_lease; -struct sd_dhcp_route; - -sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease); -sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease); - -int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime); -int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu); -int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname); -int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname); -int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path); -int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routesgn); -int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, uint8_t **data); -int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id, - size_t *client_id_len); - -int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file); -int sd_dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file); - -#endif diff --git a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h deleted file mode 100644 index 38c1c3fb..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-client.h +++ /dev/null @@ -1,66 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosddhcp6clienthfoo -#define foosddhcp6clienthfoo - -/*** - This file is part of systemd. - - Copyright (C) 2014 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include - -#include "sd-event.h" - -#include "sd-dhcp6-lease.h" - -enum { - DHCP6_EVENT_STOP = 0, - DHCP6_EVENT_RESEND_EXPIRE = 10, - DHCP6_EVENT_RETRANS_MAX = 11, - DHCP6_EVENT_IP_ACQUIRE = 12, -}; - -typedef struct sd_dhcp6_client sd_dhcp6_client; - -typedef void (*sd_dhcp6_client_cb_t)(sd_dhcp6_client *client, int event, - void *userdata); -int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, - sd_dhcp6_client_cb_t cb, void *userdata); - -int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); -int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, - size_t addr_len, uint16_t arp_type); -int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, - size_t duid_len); -int sd_dhcp6_client_set_ifname(sd_dhcp6_client *client, const char *ifname); -int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, - uint16_t option); - -int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret); - -int sd_dhcp6_client_stop(sd_dhcp6_client *client); -int sd_dhcp6_client_start(sd_dhcp6_client *client); -int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, - int priority); -int sd_dhcp6_client_detach_event(sd_dhcp6_client *client); -sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client); -sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client); -sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client); -int sd_dhcp6_client_new(sd_dhcp6_client **ret); - -#endif diff --git a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-lease.h b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-lease.h deleted file mode 100644 index 1126f1ac..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-dhcp6-lease.h +++ /dev/null @@ -1,42 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosddhcp6leasehfoo -#define foosddhcp6leasehfoo - -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include - -typedef struct sd_dhcp6_lease sd_dhcp6_lease; - -int sd_dhcp6_lease_get_first_address(sd_dhcp6_lease *lease, - struct in6_addr *addr, - uint32_t *lifetime_preferred, - uint32_t *lifetime_valid); -int sd_dhcp6_lease_get_next_address(sd_dhcp6_lease *lease, - struct in6_addr *addr, - uint32_t *lifetime_preferred, - uint32_t *lifetime_valid); - -sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease); -sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease); - -#endif diff --git a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-event.h b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-event.h deleted file mode 100644 index 25a10f99..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-event.h +++ /dev/null @@ -1,135 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosdeventhfoo -#define foosdeventhfoo - -/*** - This file is part of systemd. - - Copyright 2013 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "_sd-common.h" - -/* - Why is this better than pure epoll? - - - Supports event source prioritization - - Scales better with a large number of time events because it does not require one timerfd each - - Automatically tries to coalesce timer events system-wide - - Handles signals and child PIDs -*/ - -_SD_BEGIN_DECLARATIONS; - -typedef struct sd_event sd_event; -typedef struct sd_event_source sd_event_source; - -enum { - SD_EVENT_OFF = 0, - SD_EVENT_ON = 1, - SD_EVENT_ONESHOT = -1 -}; - -enum { - SD_EVENT_PASSIVE, - SD_EVENT_PREPARED, - SD_EVENT_PENDING, - SD_EVENT_RUNNING, - SD_EVENT_EXITING, - SD_EVENT_FINISHED -}; - -enum { - /* And everything in-between and outside is good too */ - SD_EVENT_PRIORITY_IMPORTANT = -100, - SD_EVENT_PRIORITY_NORMAL = 0, - SD_EVENT_PRIORITY_IDLE = 100 -}; - -typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata); -typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata); -typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata); -typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata); -typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata); - -int sd_event_default(sd_event **e); - -int sd_event_new(sd_event **e); -sd_event* sd_event_ref(sd_event *e); -sd_event* sd_event_unref(sd_event *e); - -int sd_event_add_io(sd_event *e, sd_event_source **s, int fd, uint32_t events, sd_event_io_handler_t callback, void *userdata); -int sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata); -int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_signal_handler_t callback, void *userdata); -int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata); -int sd_event_add_defer(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); -int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); -int sd_event_add_exit(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); - -int sd_event_prepare(sd_event *e); -int sd_event_wait(sd_event *e, uint64_t timeout); -int sd_event_dispatch(sd_event *e); -int sd_event_run(sd_event *e, uint64_t timeout); -int sd_event_loop(sd_event *e); -int sd_event_exit(sd_event *e, int code); - -int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec); - -int sd_event_get_fd(sd_event *e); -int sd_event_get_state(sd_event *e); -int sd_event_get_tid(sd_event *e, pid_t *tid); -int sd_event_get_exit_code(sd_event *e, int *code); -int sd_event_set_watchdog(sd_event *e, int b); -int sd_event_get_watchdog(sd_event *e); - -sd_event_source* sd_event_source_ref(sd_event_source *s); -sd_event_source* sd_event_source_unref(sd_event_source *s); - -sd_event *sd_event_source_get_event(sd_event_source *s); -void* sd_event_source_get_userdata(sd_event_source *s); -void* sd_event_source_set_userdata(sd_event_source *s, void *userdata); - -int sd_event_source_set_description(sd_event_source *s, const char *description); -int sd_event_source_get_description(sd_event_source *s, const char **description); -int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback); -int sd_event_source_get_pending(sd_event_source *s); -int sd_event_source_get_priority(sd_event_source *s, int64_t *priority); -int sd_event_source_set_priority(sd_event_source *s, int64_t priority); -int sd_event_source_get_enabled(sd_event_source *s, int *enabled); -int sd_event_source_set_enabled(sd_event_source *s, int enabled); -int sd_event_source_get_io_fd(sd_event_source *s); -int sd_event_source_set_io_fd(sd_event_source *s, int fd); -int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events); -int sd_event_source_set_io_events(sd_event_source *s, uint32_t events); -int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents); -int sd_event_source_get_time(sd_event_source *s, uint64_t *usec); -int sd_event_source_set_time(sd_event_source *s, uint64_t usec); -int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec); -int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec); -int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock); -int sd_event_source_get_signal(sd_event_source *s); -int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-id128.h b/src/dhcp-manager/systemd-dhcp/src/systemd/sd-id128.h deleted file mode 100644 index 4fdbf3ab..00000000 --- a/src/dhcp-manager/systemd-dhcp/src/systemd/sd-id128.h +++ /dev/null @@ -1,113 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -#ifndef foosdid128hfoo -#define foosdid128hfoo - -/*** - This file is part of systemd. - - Copyright 2011 Lennart Poettering - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "_sd-common.h" - -_SD_BEGIN_DECLARATIONS; - -/* 128-bit ID APIs. See sd-id128(3) for more information. */ - -typedef union sd_id128 sd_id128_t; - -union sd_id128 { - uint8_t bytes[16]; - uint64_t qwords[2]; -}; - -#define SD_ID128_STRING_MAX 33 - -char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]); - -int sd_id128_from_string(const char *s, sd_id128_t *ret); - -int sd_id128_randomize(sd_id128_t *ret); - -int sd_id128_get_machine(sd_id128_t *ret); - -int sd_id128_get_boot(sd_id128_t *ret); - -#define SD_ID128_MAKE(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \ - ((const sd_id128_t) { .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \ - 0x##v8, 0x##v9, 0x##v10, 0x##v11, 0x##v12, 0x##v13, 0x##v14, 0x##v15 }}) - -#define SD_ID128_ARRAY(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \ - { .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \ - 0x##v8, 0x##v9, 0x##v10, 0x##v11, 0x##v12, 0x##v13, 0x##v14, 0x##v15 }} - -/* Note that SD_ID128_FORMAT_VAL will evaluate the passed argument 16 - * times. It is hence not a good idea to call this macro with an - * expensive function as paramater or an expression with side - * effects */ - -#define SD_ID128_FORMAT_STR "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" -#define SD_ID128_FORMAT_VAL(x) (x).bytes[0], (x).bytes[1], (x).bytes[2], (x).bytes[3], (x).bytes[4], (x).bytes[5], (x).bytes[6], (x).bytes[7], (x).bytes[8], (x).bytes[9], (x).bytes[10], (x).bytes[11], (x).bytes[12], (x).bytes[13], (x).bytes[14], (x).bytes[15] - -#define SD_ID128_CONST_STR(x) \ - ((const char[SD_ID128_STRING_MAX]) { \ - ((x).bytes[0] >> 4) >= 10 ? 'a' + ((x).bytes[0] >> 4) - 10 : '0' + ((x).bytes[0] >> 4), \ - ((x).bytes[0] & 15) >= 10 ? 'a' + ((x).bytes[0] & 15) - 10 : '0' + ((x).bytes[0] & 15), \ - ((x).bytes[1] >> 4) >= 10 ? 'a' + ((x).bytes[1] >> 4) - 10 : '0' + ((x).bytes[1] >> 4), \ - ((x).bytes[1] & 15) >= 10 ? 'a' + ((x).bytes[1] & 15) - 10 : '0' + ((x).bytes[1] & 15), \ - ((x).bytes[2] >> 4) >= 10 ? 'a' + ((x).bytes[2] >> 4) - 10 : '0' + ((x).bytes[2] >> 4), \ - ((x).bytes[2] & 15) >= 10 ? 'a' + ((x).bytes[2] & 15) - 10 : '0' + ((x).bytes[2] & 15), \ - ((x).bytes[3] >> 4) >= 10 ? 'a' + ((x).bytes[3] >> 4) - 10 : '0' + ((x).bytes[3] >> 4), \ - ((x).bytes[3] & 15) >= 10 ? 'a' + ((x).bytes[3] & 15) - 10 : '0' + ((x).bytes[3] & 15), \ - ((x).bytes[4] >> 4) >= 10 ? 'a' + ((x).bytes[4] >> 4) - 10 : '0' + ((x).bytes[4] >> 4), \ - ((x).bytes[4] & 15) >= 10 ? 'a' + ((x).bytes[4] & 15) - 10 : '0' + ((x).bytes[4] & 15), \ - ((x).bytes[5] >> 4) >= 10 ? 'a' + ((x).bytes[5] >> 4) - 10 : '0' + ((x).bytes[5] >> 4), \ - ((x).bytes[5] & 15) >= 10 ? 'a' + ((x).bytes[5] & 15) - 10 : '0' + ((x).bytes[5] & 15), \ - ((x).bytes[6] >> 4) >= 10 ? 'a' + ((x).bytes[6] >> 4) - 10 : '0' + ((x).bytes[6] >> 4), \ - ((x).bytes[6] & 15) >= 10 ? 'a' + ((x).bytes[6] & 15) - 10 : '0' + ((x).bytes[6] & 15), \ - ((x).bytes[7] >> 4) >= 10 ? 'a' + ((x).bytes[7] >> 4) - 10 : '0' + ((x).bytes[7] >> 4), \ - ((x).bytes[7] & 15) >= 10 ? 'a' + ((x).bytes[7] & 15) - 10 : '0' + ((x).bytes[7] & 15), \ - ((x).bytes[8] >> 4) >= 10 ? 'a' + ((x).bytes[8] >> 4) - 10 : '0' + ((x).bytes[8] >> 4), \ - ((x).bytes[8] & 15) >= 10 ? 'a' + ((x).bytes[8] & 15) - 10 : '0' + ((x).bytes[8] & 15), \ - ((x).bytes[9] >> 4) >= 10 ? 'a' + ((x).bytes[9] >> 4) - 10 : '0' + ((x).bytes[9] >> 4), \ - ((x).bytes[9] & 15) >= 10 ? 'a' + ((x).bytes[9] & 15) - 10 : '0' + ((x).bytes[9] & 15), \ - ((x).bytes[10] >> 4) >= 10 ? 'a' + ((x).bytes[10] >> 4) - 10 : '0' + ((x).bytes[10] >> 4), \ - ((x).bytes[10] & 15) >= 10 ? 'a' + ((x).bytes[10] & 15) - 10 : '0' + ((x).bytes[10] & 15), \ - ((x).bytes[11] >> 4) >= 10 ? 'a' + ((x).bytes[11] >> 4) - 10 : '0' + ((x).bytes[11] >> 4), \ - ((x).bytes[11] & 15) >= 10 ? 'a' + ((x).bytes[11] & 15) - 10 : '0' + ((x).bytes[11] & 15), \ - ((x).bytes[12] >> 4) >= 10 ? 'a' + ((x).bytes[12] >> 4) - 10 : '0' + ((x).bytes[12] >> 4), \ - ((x).bytes[12] & 15) >= 10 ? 'a' + ((x).bytes[12] & 15) - 10 : '0' + ((x).bytes[12] & 15), \ - ((x).bytes[13] >> 4) >= 10 ? 'a' + ((x).bytes[13] >> 4) - 10 : '0' + ((x).bytes[13] >> 4), \ - ((x).bytes[13] & 15) >= 10 ? 'a' + ((x).bytes[13] & 15) - 10 : '0' + ((x).bytes[13] & 15), \ - ((x).bytes[14] >> 4) >= 10 ? 'a' + ((x).bytes[14] >> 4) - 10 : '0' + ((x).bytes[14] >> 4), \ - ((x).bytes[14] & 15) >= 10 ? 'a' + ((x).bytes[14] & 15) - 10 : '0' + ((x).bytes[14] & 15), \ - ((x).bytes[15] >> 4) >= 10 ? 'a' + ((x).bytes[15] >> 4) - 10 : '0' + ((x).bytes[15] >> 4), \ - ((x).bytes[15] & 15) >= 10 ? 'a' + ((x).bytes[15] & 15) - 10 : '0' + ((x).bytes[15] & 15), \ - 0 }) - -_sd_pure_ static inline int sd_id128_equal(sd_id128_t a, sd_id128_t b) { - return memcmp(&a, &b, 16) == 0; -} - -#define SD_ID128_NULL ((const sd_id128_t) { .qwords = { 0, 0 }}) - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/dhcp-manager/tests/Makefile.am b/src/dhcp-manager/tests/Makefile.am index 4c4c7e81..5c7f9ba2 100644 --- a/src/dhcp-manager/tests/Makefile.am +++ b/src/dhcp-manager/tests/Makefile.am @@ -1,13 +1,13 @@ AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I${top_builddir}/include \ + -I$(top_srcdir)/shared \ + -I${top_builddir}/shared \ -I${top_srcdir}/libnm-core \ -I${top_builddir}/libnm-core \ -I$(top_srcdir)/src/dhcp-manager \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/platform \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ -DTESTDIR="\"$(abs_srcdir)\"" diff --git a/src/dhcp-manager/tests/Makefile.in b/src/dhcp-manager/tests/Makefile.in index c98dbd5f..3bc370b8 100644 --- a/src/dhcp-manager/tests/Makefile.in +++ b/src/dhcp-manager/tests/Makefile.in @@ -409,7 +409,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -421,8 +420,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -432,6 +429,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -486,16 +484,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -532,6 +527,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -560,7 +557,6 @@ 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@ @@ -575,6 +571,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -635,6 +633,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -642,6 +641,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -658,15 +658,15 @@ with_netconfig = @with_netconfig@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I${top_builddir}/include \ + -I$(top_srcdir)/shared \ + -I${top_builddir}/shared \ -I${top_srcdir}/libnm-core \ -I${top_builddir}/libnm-core \ -I$(top_srcdir)/src/dhcp-manager \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/platform \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ -DTESTDIR="\"$(abs_srcdir)\"" diff --git a/src/dhcp-manager/tests/test-dhcp-dhclient.c b/src/dhcp-manager/tests/test-dhcp-dhclient.c index 459915e3..f9e1e1eb 100644 --- a/src/dhcp-manager/tests/test-dhcp-dhclient.c +++ b/src/dhcp-manager/tests/test-dhcp-dhclient.c @@ -20,12 +20,11 @@ #include "config.h" -#include #include #include #include -#include "gsystem-local-alloc.h" +#include "nm-default.h" #include "NetworkManagerUtils.h" #include "nm-dhcp-dhclient-utils.h" #include "nm-dhcp-utils.h" @@ -34,6 +33,8 @@ #include "nm-platform.h" #include "nm-macros-internal.h" +#include "nm-test-utils.h" + #define DEBUG 1 static void @@ -41,6 +42,7 @@ test_config (const char *orig, const char *expected, gboolean ipv6, const char *hostname, + const char *fqdn, const char *dhcp_client_id, GBytes *expected_new_client_id, const char *iface, @@ -60,6 +62,7 @@ test_config (const char *orig, client_id, anycast_addr, hostname, + fqdn, "/path/to/dhclient.conf", orig, &new_client_id); @@ -104,7 +107,7 @@ static const char *orig_missing_expected = \ static void test_orig_missing (void) { - test_config (NULL, orig_missing_expected, FALSE, NULL, NULL, NULL, "eth0", NULL); + test_config (NULL, orig_missing_expected, FALSE, NULL, NULL, NULL, NULL, "eth0", NULL); } /*******************************************/ @@ -133,7 +136,7 @@ static void test_override_client_id (void) { test_config (override_client_id_orig, override_client_id_expected, - FALSE, NULL, + FALSE, NULL, NULL, "11:22:33:44:55:66", NULL, "eth0", @@ -162,7 +165,7 @@ static void test_quote_client_id (void) { test_config (NULL, quote_client_id_expected, - FALSE, NULL, + FALSE, NULL, NULL, "1234", NULL, "eth0", @@ -191,7 +194,7 @@ static void test_ascii_client_id (void) { test_config (NULL, ascii_client_id_expected, - FALSE, NULL, + FALSE, NULL, NULL, "qb:cd:ef:12:34:56", NULL, "eth0", @@ -220,7 +223,7 @@ static void test_hex_single_client_id (void) { test_config (NULL, hex_single_client_id_expected, - FALSE, NULL, + FALSE, NULL, NULL, "ab:cd:e:12:34:56", NULL, "eth0", @@ -257,7 +260,7 @@ test_existing_hex_client_id (void) new_client_id = g_bytes_new (bytes, sizeof (bytes)); test_config (existing_hex_client_id_orig, existing_hex_client_id_expected, - FALSE, NULL, + FALSE, NULL, NULL, NULL, new_client_id, "eth0", @@ -297,12 +300,41 @@ test_existing_ascii_client_id (void) memcpy (buf + 1, EACID, STRLEN (EACID)); new_client_id = g_bytes_new (buf, sizeof (buf)); test_config (existing_ascii_client_id_orig, existing_ascii_client_id_expected, - FALSE, NULL, + FALSE, NULL, NULL, NULL, new_client_id, "eth0", NULL); } +/*******************************************/ + +static const char *fqdn_expected = \ + "# Created by NetworkManager\n" + "\n" + "send fqdn.fqdn \"foo.bar.com\"; # added by NetworkManager\n" + "send fqdn.encoded on;\n" + "send fqdn.server-update on;\n" + "\n" + "option rfc3442-classless-static-routes code 121 = array of unsigned integer 8;\n" + "option ms-classless-static-routes code 249 = array of unsigned integer 8;\n" + "option wpad code 252 = string;\n" + "\n" + "also request rfc3442-classless-static-routes;\n" + "also request ms-classless-static-routes;\n" + "also request static-routes;\n" + "also request wpad;\n" + "also request ntp-servers;\n\n"; + +static void +test_fqdn (void) +{ + test_config (NULL, fqdn_expected, + FALSE, NULL, + "foo.bar.com", NULL, + NULL, + "eth0", + NULL); +} /*******************************************/ @@ -330,7 +362,7 @@ static void test_override_hostname (void) { test_config (override_hostname_orig, override_hostname_expected, - FALSE, "blahblah", + FALSE, "blahblah", NULL, NULL, NULL, "eth0", @@ -359,7 +391,7 @@ static void test_override_hostname6 (void) { test_config (override_hostname6_orig, override_hostname6_expected, - TRUE, "blahblah.local", + TRUE, "blahblah.local", NULL, NULL, NULL, "eth0", @@ -382,7 +414,7 @@ test_nonfqdn_hostname6 (void) /* Non-FQDN hostname can't be used with dhclient */ test_config (NULL, nonfqdn_hostname6_expected, TRUE, "blahblah", - NULL, + NULL, NULL, NULL, "eth0", NULL); @@ -419,6 +451,7 @@ test_existing_alsoreq (void) FALSE, NULL, NULL, NULL, + NULL, "eth0", NULL); } @@ -455,7 +488,7 @@ static void test_existing_multiline_alsoreq (void) { test_config (existing_multiline_alsoreq_orig, existing_multiline_alsoreq_expected, - FALSE, NULL, + FALSE, NULL, NULL, NULL, NULL, "eth0", @@ -653,7 +686,7 @@ test_read_lease_ip4_config_basic (void) /* Date from before the least expiration */ now = g_date_time_new_utc (2013, 11, 1, 19, 55, 32); - leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", contents, FALSE, now); + leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", -1, contents, FALSE, now); g_assert_cmpint (g_slist_length (leases), ==, 2); /* IP4Config #1 */ @@ -665,6 +698,7 @@ test_read_lease_ip4_config_basic (void) g_assert (inet_aton ("192.168.1.180", (struct in_addr *) &expected_addr)); addr = nm_ip4_config_get_address (config, 0); g_assert_cmpint (addr->address, ==, expected_addr); + g_assert_cmpint (addr->peer_address, ==, expected_addr); g_assert_cmpint (addr->plen, ==, 24); /* Gateway */ @@ -687,6 +721,7 @@ test_read_lease_ip4_config_basic (void) g_assert (inet_aton ("10.77.52.141", (struct in_addr *) &expected_addr)); addr = nm_ip4_config_get_address (config, 0); g_assert_cmpint (addr->address, ==, expected_addr); + g_assert_cmpint (addr->peer_address, ==, expected_addr); g_assert_cmpint (addr->plen, ==, 8); /* Gateway */ @@ -725,7 +760,7 @@ test_read_lease_ip4_config_expired (void) /* Date from *after* the lease expiration */ now = g_date_time_new_utc (2013, 12, 1, 19, 55, 32); - leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", contents, FALSE, now); + leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", -1, contents, FALSE, now); g_assert (leases == NULL); g_date_time_unref (now); @@ -747,7 +782,7 @@ test_read_lease_ip4_config_expect_failure (gconstpointer user_data) /* Date from before the least expiration */ now = g_date_time_new_utc (2013, 11, 1, 1, 1, 1); - leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", contents, FALSE, now); + leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", -1, contents, FALSE, now); g_assert (leases == NULL); g_date_time_unref (now); @@ -756,14 +791,12 @@ test_read_lease_ip4_config_expect_failure (gconstpointer user_data) /*******************************************/ +NMTST_DEFINE (); + int main (int argc, char **argv) { - g_test_init (&argc, &argv, NULL); - -#if !GLIB_CHECK_VERSION (2, 35, 0) - g_type_init (); -#endif + nmtst_init_with_logging (&argc, &argv, NULL, "DEFAULT"); g_test_add_func ("/dhcp/dhclient/orig_missing", test_orig_missing); g_test_add_func ("/dhcp/dhclient/override_client_id", test_override_client_id); @@ -772,6 +805,7 @@ main (int argc, char **argv) g_test_add_func ("/dhcp/dhclient/hex_single_client_id", test_hex_single_client_id); g_test_add_func ("/dhcp/dhclient/existing-hex-client-id", test_existing_hex_client_id); g_test_add_func ("/dhcp/dhclient/existing-ascii-client-id", test_existing_ascii_client_id); + g_test_add_func ("/dhcp/dhclient/fqdn", test_fqdn); g_test_add_func ("/dhcp/dhclient/override_hostname", test_override_hostname); g_test_add_func ("/dhcp/dhclient/override_hostname6", test_override_hostname6); g_test_add_func ("/dhcp/dhclient/nonfqdn_hostname6", test_nonfqdn_hostname6); diff --git a/src/dhcp-manager/tests/test-dhcp-utils.c b/src/dhcp-manager/tests/test-dhcp-utils.c index 618188df..49987c40 100644 --- a/src/dhcp-manager/tests/test-dhcp-utils.c +++ b/src/dhcp-manager/tests/test-dhcp-utils.c @@ -19,15 +19,14 @@ #include "config.h" -#include #include #include #include #include +#include "nm-default.h" #include "nm-dhcp-utils.h" -#include "nm-logging.h" #include "nm-platform.h" #include "nm-test-utils.h" @@ -88,7 +87,7 @@ test_generic_options (void) const char *expected_route2_gw = "10.1.1.1"; options = fill_table (generic_options, NULL); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); /* IP4 address */ @@ -96,7 +95,7 @@ test_generic_options (void) address = nm_ip4_config_get_address (ip4_config, 0); g_assert (inet_pton (AF_INET, expected_addr, &tmp) > 0); g_assert (address->address == tmp); - g_assert (address->peer_address == 0); + g_assert (address->peer_address == tmp); g_assert_cmpint (address->plen, ==, 24); /* Gateway */ @@ -159,7 +158,7 @@ test_wins_options (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); /* IP4 address */ @@ -186,7 +185,7 @@ test_vendor_option_metered (void) }; options = fill_table (generic_options, NULL); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); g_assert (nm_ip4_config_get_metered (ip4_config) == FALSE); g_hash_table_destroy (options); @@ -194,7 +193,7 @@ test_vendor_option_metered (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); g_assert (nm_ip4_config_get_metered (ip4_config) == TRUE); g_hash_table_destroy (options); @@ -246,7 +245,7 @@ test_classless_static_routes_1 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); /* IP4 routes */ @@ -274,7 +273,7 @@ test_classless_static_routes_2 (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); /* IP4 routes */ @@ -303,7 +302,7 @@ test_fedora_dhclient_classless_static_routes (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); /* IP4 routes */ @@ -335,7 +334,7 @@ test_dhclient_invalid_classless_routes_1 (void) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*ignoring invalid classless static routes*"); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); g_test_assert_expected_messages (); @@ -366,7 +365,7 @@ test_dhcpcd_invalid_classless_routes_1 (void) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*ignoring invalid classless static routes*"); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); g_test_assert_expected_messages (); @@ -399,7 +398,7 @@ test_dhclient_invalid_classless_routes_2 (void) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*ignoring invalid classless static routes*"); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); g_test_assert_expected_messages (); @@ -432,7 +431,7 @@ test_dhcpcd_invalid_classless_routes_2 (void) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*ignoring invalid classless static routes*"); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); g_test_assert_expected_messages (); @@ -465,7 +464,7 @@ test_dhclient_invalid_classless_routes_3 (void) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*ignoring invalid classless static routes*"); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); g_test_assert_expected_messages (); @@ -493,7 +492,7 @@ test_dhcpcd_invalid_classless_routes_3 (void) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*DHCP provided invalid classless static route*"); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); g_test_assert_expected_messages (); @@ -519,7 +518,7 @@ test_dhclient_gw_in_classless_routes (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); /* IP4 routes */ @@ -547,7 +546,7 @@ test_dhcpcd_gw_in_classless_routes (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); /* IP4 routes */ @@ -575,7 +574,7 @@ test_escaped_domain_searches (void) options = fill_table (generic_options, NULL); options = fill_table (data, options); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); /* domain searches */ @@ -602,7 +601,7 @@ test_invalid_escaped_domain_searches (void) g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*invalid domain search*"); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); g_test_assert_expected_messages (); @@ -623,7 +622,7 @@ test_ip4_missing_prefix (const char *ip, guint32 expected_prefix) g_hash_table_insert (options, "ip_address", (gpointer) ip); g_hash_table_remove (options, "subnet_mask"); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1); @@ -668,7 +667,7 @@ test_ip4_prefix_classless (void) g_hash_table_insert (options, "ip_address", "172.16.54.22"); g_hash_table_insert (options, "subnet_mask", "255.255.252.0"); - ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0); + ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0); g_assert (ip4_config); g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1); diff --git a/src/dns-manager/nm-dns-dnsmasq.c b/src/dns-manager/nm-dns-dnsmasq.c index f26ccfaa..63e37bf3 100644 --- a/src/dns-manager/nm-dns-dnsmasq.c +++ b/src/dns-manager/nm-dns-dnsmasq.c @@ -27,12 +27,9 @@ #include #include -#include -#include - +#include "nm-default.h" #include "nm-dns-dnsmasq.h" #include "nm-utils.h" -#include "nm-logging.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" #include "nm-dns-utils.h" @@ -138,6 +135,30 @@ ip6_addr_to_string (const struct in6_addr *addr, const char *iface) return buf; } +static void +add_global_config (GString *str, const NMGlobalDnsConfig *config) +{ + guint i, j; + + g_return_if_fail (config); + + for (i = 0; i < nm_global_dns_config_get_num_domains (config); i++) { + NMGlobalDnsDomain *domain = nm_global_dns_config_get_domain (config, i); + const char *const *servers = nm_global_dns_domain_get_servers (domain); + + for (j = 0; servers && servers[j]; j++) { + if (!strcmp (servers[j], "*")) + g_string_append_printf (str, "server=%s\n", servers[j]); + else { + g_string_append_printf (str, "server=/%s/%s\n", + nm_global_dns_domain_get_name (domain), + servers[j]); + } + } + + } +} + static gboolean add_ip6_config (GString *str, NMIP6Config *ip6, gboolean split) { @@ -204,6 +225,7 @@ update (NMDnsPlugin *plugin, const GSList *vpn_configs, const GSList *dev_configs, const GSList *other_configs, + const NMGlobalDnsConfig *global_config, const char *hostname) { NMDnsDnsmasq *self = NM_DNS_DNSMASQ (plugin); @@ -232,28 +254,32 @@ update (NMDnsPlugin *plugin, /* Build up the new dnsmasq config file */ conf = g_string_sized_new (150); - /* Use split DNS for VPN configs */ - for (iter = (GSList *) vpn_configs; iter; iter = g_slist_next (iter)) { - if (NM_IS_IP4_CONFIG (iter->data)) - add_ip4_config (conf, NM_IP4_CONFIG (iter->data), TRUE); - else if (NM_IS_IP6_CONFIG (iter->data)) - add_ip6_config (conf, NM_IP6_CONFIG (iter->data), TRUE); - } + if (global_config) + add_global_config (conf, global_config); + else { + /* Use split DNS for VPN configs */ + for (iter = (GSList *) vpn_configs; iter; iter = g_slist_next (iter)) { + if (NM_IS_IP4_CONFIG (iter->data)) + add_ip4_config (conf, NM_IP4_CONFIG (iter->data), TRUE); + else if (NM_IS_IP6_CONFIG (iter->data)) + add_ip6_config (conf, NM_IP6_CONFIG (iter->data), TRUE); + } - /* Now add interface configs without split DNS */ - for (iter = (GSList *) dev_configs; iter; iter = g_slist_next (iter)) { - if (NM_IS_IP4_CONFIG (iter->data)) - add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE); - else if (NM_IS_IP6_CONFIG (iter->data)) - add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE); - } + /* Now add interface configs without split DNS */ + for (iter = (GSList *) dev_configs; iter; iter = g_slist_next (iter)) { + if (NM_IS_IP4_CONFIG (iter->data)) + add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE); + else if (NM_IS_IP6_CONFIG (iter->data)) + add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE); + } - /* And any other random configs */ - for (iter = (GSList *) other_configs; iter; iter = g_slist_next (iter)) { - if (NM_IS_IP4_CONFIG (iter->data)) - add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE); - else if (NM_IS_IP6_CONFIG (iter->data)) - add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE); + /* And any other random configs */ + for (iter = (GSList *) other_configs; iter; iter = g_slist_next (iter)) { + if (NM_IS_IP4_CONFIG (iter->data)) + add_ip4_config (conf, NM_IP4_CONFIG (iter->data), FALSE); + else if (NM_IS_IP6_CONFIG (iter->data)) + add_ip6_config (conf, NM_IP6_CONFIG (iter->data), FALSE); + } } /* Write out the config file */ diff --git a/src/dns-manager/nm-dns-dnsmasq.h b/src/dns-manager/nm-dns-dnsmasq.h index fc80f079..f0393c12 100644 --- a/src/dns-manager/nm-dns-dnsmasq.h +++ b/src/dns-manager/nm-dns-dnsmasq.h @@ -19,9 +19,6 @@ #ifndef __NETWORKMANAGER_DNS_DNSMASQ_H__ #define __NETWORKMANAGER_DNS_DNSMASQ_H__ -#include -#include - #include "nm-dns-plugin.h" #define NM_TYPE_DNS_DNSMASQ (nm_dns_dnsmasq_get_type ()) diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c index c4be7df2..01e8bf1d 100644 --- a/src/dns-manager/nm-dns-manager.c +++ b/src/dns-manager/nm-dns-manager.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -34,14 +35,12 @@ #include -#include -#include - +#include "nm-default.h" #include "nm-utils.h" +#include "nm-core-internal.h" #include "nm-dns-manager.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" -#include "nm-logging.h" #include "NetworkManagerUtils.h" #include "nm-config.h" @@ -71,6 +70,47 @@ G_DEFINE_TYPE (NMDnsManager, nm_dns_manager, G_TYPE_OBJECT) #define HASH_LEN 20 +#ifdef RESOLVCONF_PATH +#define RESOLVCONF_SELECTED +#else +#define RESOLVCONF_PATH "/sbin/resolvconf" +#endif + +#ifdef NETCONFIG_PATH +#define NETCONFIG_SELECTED +#else +#define NETCONFIG_PATH "/sbin/netconfig" +#endif + +NM_DEFINE_SINGLETON_INSTANCE (NMDnsManager); + +/*********************************************************************************************/ + +#define _NMLOG_PREFIX_NAME "dns-mgr" +#define _NMLOG_DOMAIN LOGD_DNS +#define _NMLOG(level, ...) \ + G_STMT_START { \ + const NMLogLevel __level = (level); \ + \ + if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \ + char __prefix[20]; \ + const NMDnsManager *const __self = (self); \ + \ + _nm_log (__level, _NMLOG_DOMAIN, 0, \ + "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + ((__self == singleton_instance) \ + ? _NMLOG_PREFIX_NAME \ + : ({ \ + g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \ + __prefix; \ + }) \ + ) \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } \ + } G_STMT_END + +/*********************************************************************************************/ + typedef struct { NMIP4Config *ip4_vpn_config; NMIP4Config *ip4_device_config; @@ -84,6 +124,7 @@ typedef struct { guint8 prev_hash[HASH_LEN]; /* Hash when begin_updates() was called */ NMDnsManagerResolvConfMode resolv_conf_mode; + NMDnsManagerResolvConfManager rc_manager; NMDnsPlugin *plugin; NMConfig *config; @@ -97,12 +138,19 @@ enum { LAST_SIGNAL }; +typedef enum { + SR_SUCCESS, + SR_NOTFOUND, + SR_ERROR +} SpawnResult; + static guint signals[LAST_SIGNAL] = { 0 }; typedef struct { GPtrArray *nameservers; GPtrArray *searches; + GPtrArray *options; const char *nis_domain; GPtrArray *nis_servers; } NMResolvConfData; @@ -127,6 +175,13 @@ add_string_item (GPtrArray *array, const char *str) g_ptr_array_add (array, g_strdup (str)); } +static void +add_dns_option_item (GPtrArray *array, const char *str, gboolean ipv6) +{ + if (_nm_utils_dns_option_find_idx (array, str) < 0) + g_ptr_array_add (array, g_strdup (str)); +} + static void merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src) { @@ -161,6 +216,14 @@ merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src) } } + num = nm_ip4_config_get_num_dns_options (src); + for (i = 0; i < num; i++) { + const char *option; + + option = nm_ip4_config_get_dns_option (src, i); + add_dns_option_item (rc->options, option, FALSE); + } + /* NIS stuff */ num = nm_ip4_config_get_num_nis_servers (src); for (i = 0; i < num; i++) { @@ -225,18 +288,21 @@ merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src) add_string_item (rc->searches, domain); } } -} + num = nm_ip6_config_get_num_dns_options (src); + for (i = 0; i < num; i++) { + const char *option; -#if defined(NETCONFIG_PATH) -/**********************************/ -/* SUSE */ + option = nm_ip6_config_get_dns_option (src, i); + add_dns_option_item (rc->options, option, TRUE); + } +} static GPid -run_netconfig (GError **error, gint *stdin_fd) +run_netconfig (NMDnsManager *self, GError **error, gint *stdin_fd) { char *argv[5]; - char *tmp; + gs_free char *tmp = NULL; GPid pid = -1; argv[0] = NETCONFIG_PATH; @@ -245,9 +311,8 @@ run_netconfig (GError **error, gint *stdin_fd) argv[3] = "NetworkManager"; argv[4] = NULL; - tmp = g_strjoinv (" ", argv); - nm_log_dbg (LOGD_DNS, "spawning '%s'", tmp); - g_free (tmp); + _LOGD ("spawning '%s'", + (tmp = g_strjoinv (" ", argv))); if (!g_spawn_async_with_pipes (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, stdin_fd, NULL, NULL, error)) @@ -257,19 +322,20 @@ run_netconfig (GError **error, gint *stdin_fd) } static void -write_to_netconfig (gint fd, const char *key, const char *value) +write_to_netconfig (NMDnsManager *self, gint fd, const char *key, const char *value) { char *str; int x; str = g_strdup_printf ("%s='%s'\n", key, value); - nm_log_dbg (LOGD_DNS, "writing to netconfig: %s", str); + _LOGD ("writing to netconfig: %s", str); x = write (fd, str, strlen (str)); g_free (str); } -static gboolean -dispatch_netconfig (char **searches, +static SpawnResult +dispatch_netconfig (NMDnsManager *self, + char **searches, char **nameservers, const char *nis_domain, char **nis_servers, @@ -280,34 +346,34 @@ dispatch_netconfig (char **searches, gint fd; int status; - pid = run_netconfig (error, &fd); + pid = run_netconfig (self, error, &fd); if (pid <= 0) - return FALSE; + return SR_NOTFOUND; /* NM is writing already-merged DNS information to netconfig, so it * does not apply to a specific network interface. */ - write_to_netconfig (fd, "INTERFACE", "NetworkManager"); + write_to_netconfig (self, fd, "INTERFACE", "NetworkManager"); if (searches) { str = g_strjoinv (" ", searches); - write_to_netconfig (fd, "DNSSEARCH", str); + write_to_netconfig (self, fd, "DNSSEARCH", str); g_free (str); } if (nameservers) { str = g_strjoinv (" ", nameservers); - write_to_netconfig (fd, "DNSSERVERS", str); + write_to_netconfig (self, fd, "DNSSERVERS", str); g_free (str); } if (nis_domain) - write_to_netconfig (fd, "NISDOMAIN", nis_domain); + write_to_netconfig (self, fd, "NISDOMAIN", nis_domain); if (nis_servers) { str = g_strjoinv (" ", nis_servers); - write_to_netconfig (fd, "NISSERVERS", str); + write_to_netconfig (self, fd, "NISSERVERS", str); g_free (str); } @@ -320,28 +386,28 @@ dispatch_netconfig (char **searches, g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "Error waiting for netconfig to exit: %s", strerror (errsv)); - return FALSE; + return SR_ERROR; } if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "Error calling netconfig: %s %d", WIFEXITED (status) ? "exited with status" : (WIFSIGNALED (status) ? "exited with signal" : "exited with unknown reason"), WIFEXITED (status) ? WEXITSTATUS (status) : (WIFSIGNALED (status) ? WTERMSIG (status) : status)); - return FALSE; + return SR_ERROR; } - return TRUE; + return SR_SUCCESS; } -#endif - static gboolean write_resolv_conf (FILE *f, char **searches, char **nameservers, + char **options, GError **error) { char *searches_str = NULL; char *nameservers_str = NULL; + char *options_str = NULL; gboolean retval = FALSE; char *tmp_str; GString *str; @@ -353,6 +419,12 @@ write_resolv_conf (FILE *f, g_free (tmp_str); } + if (options) { + tmp_str = g_strjoinv (" ", options); + options_str = g_strconcat ("options ", tmp_str, "\n", NULL); + g_free (tmp_str); + } + str = g_string_new (""); if (nameservers) { @@ -375,9 +447,10 @@ write_resolv_conf (FILE *f, nameservers_str = g_string_free (str, FALSE); - if (fprintf (f, "# Generated by NetworkManager\n%s%s", + if (fprintf (f, "# Generated by NetworkManager\n%s%s%s", searches_str ? searches_str : "", - nameservers_str) > 0) + nameservers_str, + options_str ? options_str : "") > 0) retval = TRUE; else { g_set_error (error, @@ -389,14 +462,16 @@ write_resolv_conf (FILE *f, g_free (searches_str); g_free (nameservers_str); + g_free (options_str); return retval; } -#ifdef RESOLVCONF_PATH -static gboolean -dispatch_resolvconf (char **searches, +static SpawnResult +dispatch_resolvconf (NMDnsManager *self, + char **searches, char **nameservers, + char **options, GError **error) { char *cmd; @@ -409,12 +484,12 @@ dispatch_resolvconf (char **searches, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, RESOLVCONF_PATH " is not executable"); - return FALSE; + return SR_NOTFOUND; } if (searches || nameservers) { cmd = g_strconcat (RESOLVCONF_PATH, " -a ", "NetworkManager", NULL); - nm_log_info (LOGD_DNS, "Writing DNS information to %s", RESOLVCONF_PATH); + _LOGI ("Writing DNS information to %s", RESOLVCONF_PATH); if ((f = popen (cmd, "w")) == NULL) g_set_error (error, NM_MANAGER_ERROR, @@ -423,7 +498,7 @@ dispatch_resolvconf (char **searches, RESOLVCONF_PATH, g_strerror (errno)); else { - retval = write_resolv_conf (f, searches, nameservers, error); + retval = write_resolv_conf (f, searches, nameservers, options, error); err = pclose (f); if (err < 0) { errnosv = errno; @@ -431,76 +506,70 @@ dispatch_resolvconf (char **searches, "Failed to close pipe to resolvconf: %d", errnosv); retval = FALSE; } else if (err > 0) { - nm_log_warn (LOGD_DNS, "resolvconf failed with status %d", err); + _LOGW ("resolvconf failed with status %d", err); retval = FALSE; } } } else { cmd = g_strconcat (RESOLVCONF_PATH, " -d ", "NetworkManager", NULL); - nm_log_info (LOGD_DNS, "Removing DNS information from %s", RESOLVCONF_PATH); + _LOGI ("Removing DNS information from %s", RESOLVCONF_PATH); if (nm_spawn_process (cmd, error) == 0) retval = TRUE; } g_free (cmd); - return retval; + return retval ? SR_SUCCESS : SR_ERROR; } -#endif -static gboolean -update_resolv_conf (char **searches, +#define MY_RESOLV_CONF NMRUNDIR "/resolv.conf" +#define MY_RESOLV_CONF_TMP MY_RESOLV_CONF ".tmp" +#define RESOLV_CONF_TMP "/etc/.resolv.conf.NetworkManager" + +static SpawnResult +update_resolv_conf (NMDnsManager *self, + char **searches, char **nameservers, - GError **error) + char **options, + GError **error, + gboolean install_etc) { - char *tmp_resolv_conf; - char *tmp_resolv_conf_realpath; - char *resolv_conf_realpath; FILE *f; - int do_rename = 1; - int old_errno = 0; + struct stat st; + gboolean ret; - g_return_val_if_fail (error != NULL, FALSE); + /* If we are not managing /etc/resolv.conf and it points to + * MY_RESOLV_CONF, don't write the private DNS configuration to + * MY_RESOLV_CONF otherwise we would overwrite the changes done by + * some external application. + */ + if (!install_etc) { + char *path = g_file_read_link (_PATH_RESCONF, NULL); + gboolean ours = !g_strcmp0 (path, MY_RESOLV_CONF); - /* Find the real path of resolv.conf; it could be a symlink to something */ - resolv_conf_realpath = realpath (_PATH_RESCONF, NULL); - if (!resolv_conf_realpath) - resolv_conf_realpath = strdup (_PATH_RESCONF); + g_free (path); - /* Build up the real path for the temp resolv.conf that we're about to - * write out. - */ - tmp_resolv_conf = g_strdup_printf ("%s.tmp", resolv_conf_realpath); - tmp_resolv_conf_realpath = realpath (tmp_resolv_conf, NULL); - if (!tmp_resolv_conf_realpath) - tmp_resolv_conf_realpath = strdup (tmp_resolv_conf); - g_free (tmp_resolv_conf); - tmp_resolv_conf = NULL; - - if ((f = fopen (tmp_resolv_conf_realpath, "w")) == NULL) { - do_rename = 0; - old_errno = errno; - if ((f = fopen (_PATH_RESCONF, "w")) == NULL) { - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Could not open %s: %s\nCould not open %s: %s\n", - tmp_resolv_conf_realpath, - g_strerror (old_errno), - _PATH_RESCONF, - g_strerror (errno)); - goto out; + if (ours) { + _LOGD ("not updating " MY_RESOLV_CONF + " since it points to " _PATH_RESCONF); + return SR_ERROR; } - /* Update tmp_resolv_conf_realpath so the error message on fclose() - * failure will be correct. - */ - strcpy (tmp_resolv_conf_realpath, _PATH_RESCONF); } - write_resolv_conf (f, searches, nameservers, error); + if ((f = fopen (MY_RESOLV_CONF_TMP, "w")) == NULL) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "Could not open %s: %s\n", + MY_RESOLV_CONF_TMP, + g_strerror (errno)); + return SR_ERROR; + } + + ret = write_resolv_conf (f, searches, nameservers, options, error); if (fclose (f) < 0) { - if (*error == NULL) { + if (ret) { /* only set an error here if write_resolv_conf() was successful, * since its error is more important. */ @@ -508,32 +577,97 @@ update_resolv_conf (char **searches, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, "Could not close %s: %s\n", - tmp_resolv_conf_realpath, + MY_RESOLV_CONF_TMP, g_strerror (errno)); } } - /* Don't rename the tempfile over top of the existing resolv.conf if there - * was an error writing it out. - */ - if (*error == NULL && do_rename) { - if (rename (tmp_resolv_conf_realpath, resolv_conf_realpath) < 0) { - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Could not replace " _PATH_RESCONF ": %s\n", - g_strerror (errno)); + if (!ret) + return SR_ERROR; + + if (rename (MY_RESOLV_CONF_TMP, MY_RESOLV_CONF) < 0) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "Could not replace %s: %s\n", + MY_RESOLV_CONF, + g_strerror (errno)); + return SR_ERROR; + } + + if (!install_etc) + return SR_SUCCESS; + + /* Don't overwrite a symbolic link unless it points to MY_RESOLV_CONF. */ + if (lstat (_PATH_RESCONF, &st) != -1) { + /* Don't overwrite a symbolic link. */ + if (S_ISLNK (st.st_mode)) { + if (stat (_PATH_RESCONF, &st) != -1) { + char *path = g_file_read_link (_PATH_RESCONF, NULL); + gboolean not_ours = g_strcmp0 (path, MY_RESOLV_CONF) != 0; + + g_free (path); + if (not_ours) + return SR_SUCCESS; + } else { + if (errno != ENOENT) + return SR_SUCCESS; + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "Could not stat %s: %s\n", + _PATH_RESCONF, + g_strerror (errno)); + return SR_ERROR; + } } + } else if (errno != ENOENT) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "Could not lstat %s: %s\n", + _PATH_RESCONF, + g_strerror (errno)); + return SR_ERROR; } -out: - free (tmp_resolv_conf_realpath); - free (resolv_conf_realpath); - return *error ? FALSE : TRUE; + if (unlink (RESOLV_CONF_TMP) == -1 && errno != ENOENT) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "Could not unlink %s: %s\n", + RESOLV_CONF_TMP, + g_strerror (errno)); + return SR_ERROR; + } + + if (symlink (MY_RESOLV_CONF, RESOLV_CONF_TMP) == -1) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "Could not create symlink %s pointing to %s: %s\n", + RESOLV_CONF_TMP, + MY_RESOLV_CONF, + g_strerror (errno)); + return SR_ERROR; + } + + if (rename (RESOLV_CONF_TMP, _PATH_RESCONF) == -1) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "Could not rename %s to %s: %s\n", + RESOLV_CONF_TMP, + _PATH_RESCONF, + g_strerror (errno)); + return SR_ERROR; + } + + return SR_SUCCESS; } static void -compute_hash (NMDnsManager *self, guint8 buffer[HASH_LEN]) +compute_hash (NMDnsManager *self, const NMGlobalDnsConfig *global, guint8 buffer[HASH_LEN]) { NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); GChecksum *sum; @@ -543,6 +677,9 @@ compute_hash (NMDnsManager *self, guint8 buffer[HASH_LEN]) sum = g_checksum_new (G_CHECKSUM_SHA1); g_assert (len == g_checksum_type_get_length (G_CHECKSUM_SHA1)); + if (global) + nm_global_dns_config_update_checksum (global, sum); + if (priv->ip4_vpn_config) nm_ip4_config_hash (priv->ip4_vpn_config, sum, TRUE); if (priv->ip4_device_config) @@ -607,6 +744,38 @@ build_plugin_config_lists (NMDnsManager *self, } } +static gboolean +merge_global_dns_config (NMResolvConfData *rc, NMGlobalDnsConfig *global_conf) +{ + NMGlobalDnsDomain *default_domain; + const char *const *searches; + const char *const *options; + const char *const *servers; + gint i; + + if (!global_conf) + return FALSE; + + searches = nm_global_dns_config_get_searches (global_conf); + options = nm_global_dns_config_get_options (global_conf); + + for (i = 0; searches && searches[i]; i++) { + if (DOMAIN_IS_VALID (searches[i])) + add_string_item (rc->searches, searches[i]); + } + + for (i = 0; options && options[i]; i++) + add_string_item (rc->options, options[i]); + + default_domain = nm_global_dns_config_lookup_domain (global_conf, "*"); + g_assert (default_domain); + servers = nm_global_dns_domain_get_servers (default_domain); + for (i = 0; servers && servers[i]; i++) + add_string_item (rc->nameservers, servers[i]); + + return TRUE; +} + static gboolean update_dns (NMDnsManager *self, gboolean no_caching, @@ -617,57 +786,71 @@ update_dns (NMDnsManager *self, GSList *iter; const char *nis_domain = NULL; char **searches = NULL; + char **options = NULL; char **nameservers = NULL; char **nis_servers = NULL; int num, i, len; - gboolean success = FALSE, caching = FALSE; + gboolean caching = FALSE, update = TRUE; + gboolean resolv_conf_updated = FALSE; + SpawnResult result = SR_ERROR; + NMConfigData *data; + NMGlobalDnsConfig *global_config; g_return_val_if_fail (!error || !*error, FALSE); priv = NM_DNS_MANAGER_GET_PRIVATE (self); - if (priv->resolv_conf_mode == NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED) - return TRUE; - - priv->dns_touched = TRUE; + if (priv->resolv_conf_mode == NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED) { + update = FALSE; + _LOGD ("update-dns: not updating resolv.conf"); + } else { + priv->dns_touched = TRUE; + _LOGD ("update-dns: updating resolv.conf"); + } - nm_log_dbg (LOGD_DNS, "updating resolv.conf"); + data = nm_config_get_data (priv->config); + global_config = nm_config_data_get_global_dns_config (data); /* Update hash with config we're applying */ - compute_hash (self, priv->hash); + compute_hash (self, global_config, priv->hash); rc.nameservers = g_ptr_array_new (); rc.searches = g_ptr_array_new (); + rc.options = g_ptr_array_new (); rc.nis_domain = NULL; rc.nis_servers = g_ptr_array_new (); - if (priv->ip4_vpn_config) - merge_one_ip4_config (&rc, priv->ip4_vpn_config); - if (priv->ip4_device_config) - merge_one_ip4_config (&rc, priv->ip4_device_config); - - if (priv->ip6_vpn_config) - merge_one_ip6_config (&rc, priv->ip6_vpn_config); - if (priv->ip6_device_config) - merge_one_ip6_config (&rc, priv->ip6_device_config); - - for (iter = priv->configs; iter; iter = g_slist_next (iter)) { - if ( (iter->data == priv->ip4_vpn_config) - || (iter->data == priv->ip4_device_config) - || (iter->data == priv->ip6_vpn_config) - || (iter->data == priv->ip6_device_config)) - continue; + if (global_config) + merge_global_dns_config (&rc, global_config); + else { + if (priv->ip4_vpn_config) + merge_one_ip4_config (&rc, priv->ip4_vpn_config); + if (priv->ip4_device_config) + merge_one_ip4_config (&rc, priv->ip4_device_config); + + if (priv->ip6_vpn_config) + merge_one_ip6_config (&rc, priv->ip6_vpn_config); + if (priv->ip6_device_config) + merge_one_ip6_config (&rc, priv->ip6_device_config); + + for (iter = priv->configs; iter; iter = g_slist_next (iter)) { + if ( (iter->data == priv->ip4_vpn_config) + || (iter->data == priv->ip4_device_config) + || (iter->data == priv->ip6_vpn_config) + || (iter->data == priv->ip6_device_config)) + continue; - if (NM_IS_IP4_CONFIG (iter->data)) { - NMIP4Config *config = NM_IP4_CONFIG (iter->data); + if (NM_IS_IP4_CONFIG (iter->data)) { + NMIP4Config *config = NM_IP4_CONFIG (iter->data); - merge_one_ip4_config (&rc, config); - } else if (NM_IS_IP6_CONFIG (iter->data)) { - NMIP6Config *config = NM_IP6_CONFIG (iter->data); + merge_one_ip4_config (&rc, config); + } else if (NM_IS_IP6_CONFIG (iter->data)) { + NMIP6Config *config = NM_IP6_CONFIG (iter->data); - merge_one_ip6_config (&rc, config); - } else - g_assert_not_reached (); + merge_one_ip6_config (&rc, config); + } else + g_assert_not_reached (); + } } /* If the hostname is a FQDN ("dcbw.example.com"), then add the domain part of it @@ -705,6 +888,12 @@ update_dns (NMDnsManager *self, } else g_ptr_array_free (rc.searches, TRUE); + if (rc.options->len) { + g_ptr_array_add (rc.options, NULL); + options = (char **) g_ptr_array_free (rc.options, FALSE); + } else + g_ptr_array_free (rc.options, TRUE); + if (rc.nameservers->len) { g_ptr_array_add (rc.nameservers, NULL); nameservers = (char **) g_ptr_array_free (rc.nameservers, FALSE); @@ -720,29 +909,31 @@ update_dns (NMDnsManager *self, nis_domain = rc.nis_domain; /* Let any plugins do their thing first */ - if (priv->plugin) { + if (update && priv->plugin) { NMDnsPlugin *plugin = priv->plugin; const char *plugin_name = nm_dns_plugin_get_name (plugin); GSList *vpn_configs = NULL, *dev_configs = NULL, *other_configs = NULL; if (nm_dns_plugin_is_caching (plugin)) { if (no_caching) { - nm_log_dbg (LOGD_DNS, "DNS: plugin %s ignored (caching disabled)", - plugin_name); + _LOGD ("update-dns: plugin %s ignored (caching disabled)", + plugin_name); goto skip; } caching = TRUE; } - build_plugin_config_lists (self, &vpn_configs, &dev_configs, &other_configs); + if (!global_config) + build_plugin_config_lists (self, &vpn_configs, &dev_configs, &other_configs); - nm_log_dbg (LOGD_DNS, "DNS: updating plugin %s", plugin_name); + _LOGD ("update-dns: updating plugin %s", plugin_name); if (!nm_dns_plugin_update (plugin, vpn_configs, dev_configs, other_configs, + global_config, priv->hostname)) { - nm_log_warn (LOGD_DNS, "DNS: plugin %s update failed", plugin_name); + _LOGW ("update-dns: plugin %s update failed", plugin_name); /* If the plugin failed to update, we shouldn't write out a local * caching DNS configuration to resolv.conf. @@ -768,35 +959,50 @@ update_dns (NMDnsManager *self, nameservers[0] = g_strdup ("127.0.0.1"); } -#ifdef RESOLVCONF_PATH - success = dispatch_resolvconf (searches, nameservers, error); -#endif + if (update) { + switch (priv->rc_manager) { + case NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE: + result = update_resolv_conf (self, searches, nameservers, options, error, TRUE); + resolv_conf_updated = TRUE; + break; + case NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF: + result = dispatch_resolvconf (self, searches, nameservers, options, error); + break; + case NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG: + result = dispatch_netconfig (self, searches, nameservers, nis_domain, + nis_servers, error); + break; + default: + g_assert_not_reached (); + } -#ifdef NETCONFIG_PATH - if (success == FALSE) { - g_clear_error (error); - success = dispatch_netconfig (searches, nameservers, - nis_domain, nis_servers, error); + if (result == SR_NOTFOUND) { + _LOGD ("update-dns: program not available, writing to resolv.conf"); + g_clear_error (error); + result = update_resolv_conf (self, searches, nameservers, options, error, TRUE); + resolv_conf_updated = TRUE; + } } -#endif - if (success == FALSE) { - g_clear_error (error); - success = update_resolv_conf (searches, nameservers, error); - } + /* Unless we've already done it, update private resolv.conf in NMRUNDIR + ignoring any errors */ + if (!resolv_conf_updated) + update_resolv_conf (self, searches, nameservers, options, NULL, FALSE); /* signal that resolv.conf was changed */ - if (success) + if (update && result == SR_SUCCESS) g_signal_emit (self, signals[CONFIG_CHANGED], 0); if (searches) g_strfreev (searches); + if (options) + g_strfreev (options); if (nameservers) g_strfreev (nameservers); if (nis_servers) g_strfreev (nis_servers); - return success; + return !update || result == SR_SUCCESS; } static void @@ -811,7 +1017,7 @@ plugin_failed (NMDnsPlugin *plugin, gpointer user_data) /* Disable caching until the next DNS update */ if (!update_dns (self, TRUE, &error)) { - nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message); + _LOGW ("could not commit DNS changes: %s", error->message); g_clear_error (&error); } } @@ -822,18 +1028,18 @@ plugin_child_quit (NMDnsPlugin *plugin, int exit_status, gpointer user_data) NMDnsManager *self = NM_DNS_MANAGER (user_data); GError *error = NULL; - nm_log_warn (LOGD_DNS, "DNS: plugin %s child quit unexpectedly; refreshing DNS", + _LOGW ("plugin %s child quit unexpectedly; refreshing DNS", nm_dns_plugin_get_name (plugin)); /* Let the plugin try to spawn the child again */ if (!update_dns (self, FALSE, &error)) { - nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message); + _LOGW ("could not commit DNS changes: %s", error->message); g_clear_error (&error); } } gboolean -nm_dns_manager_add_ip4_config (NMDnsManager *mgr, +nm_dns_manager_add_ip4_config (NMDnsManager *self, const char *iface, NMIP4Config *config, NMDnsIPConfigType cfg_type) @@ -841,10 +1047,10 @@ nm_dns_manager_add_ip4_config (NMDnsManager *mgr, NMDnsManagerPrivate *priv; GError *error = NULL; - g_return_val_if_fail (mgr != NULL, FALSE); + g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (config != NULL, FALSE); - priv = NM_DNS_MANAGER_GET_PRIVATE (mgr); + priv = NM_DNS_MANAGER_GET_PRIVATE (self); g_object_set_data_full (G_OBJECT (config), IP_CONFIG_IFACE_TAG, g_strdup (iface), g_free); @@ -863,8 +1069,8 @@ nm_dns_manager_add_ip4_config (NMDnsManager *mgr, if (!g_slist_find (priv->configs, config)) priv->configs = g_slist_append (priv->configs, g_object_ref (config)); - if (!priv->updates_queue && !update_dns (mgr, FALSE, &error)) { - nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message); + if (!priv->updates_queue && !update_dns (self, FALSE, &error)) { + _LOGW ("could not commit DNS changes: %s", error->message); g_clear_error (&error); } @@ -872,15 +1078,15 @@ nm_dns_manager_add_ip4_config (NMDnsManager *mgr, } gboolean -nm_dns_manager_remove_ip4_config (NMDnsManager *mgr, NMIP4Config *config) +nm_dns_manager_remove_ip4_config (NMDnsManager *self, NMIP4Config *config) { NMDnsManagerPrivate *priv; GError *error = NULL; - g_return_val_if_fail (mgr != NULL, FALSE); + g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (config != NULL, FALSE); - priv = NM_DNS_MANAGER_GET_PRIVATE (mgr); + priv = NM_DNS_MANAGER_GET_PRIVATE (self); /* Can't remove it if it wasn't in the list to begin with */ if (!g_slist_find (priv->configs, config)) @@ -895,8 +1101,8 @@ nm_dns_manager_remove_ip4_config (NMDnsManager *mgr, NMIP4Config *config) g_object_unref (config); - if (!priv->updates_queue && !update_dns (mgr, FALSE, &error)) { - nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message); + if (!priv->updates_queue && !update_dns (self, FALSE, &error)) { + _LOGW ("could not commit DNS changes: %s", error->message); g_clear_error (&error); } @@ -906,7 +1112,7 @@ nm_dns_manager_remove_ip4_config (NMDnsManager *mgr, NMIP4Config *config) } gboolean -nm_dns_manager_add_ip6_config (NMDnsManager *mgr, +nm_dns_manager_add_ip6_config (NMDnsManager *self, const char *iface, NMIP6Config *config, NMDnsIPConfigType cfg_type) @@ -914,10 +1120,10 @@ nm_dns_manager_add_ip6_config (NMDnsManager *mgr, NMDnsManagerPrivate *priv; GError *error = NULL; - g_return_val_if_fail (mgr != NULL, FALSE); + g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (config != NULL, FALSE); - priv = NM_DNS_MANAGER_GET_PRIVATE (mgr); + priv = NM_DNS_MANAGER_GET_PRIVATE (self); g_object_set_data_full (G_OBJECT (config), IP_CONFIG_IFACE_TAG, g_strdup (iface), g_free); @@ -936,8 +1142,8 @@ nm_dns_manager_add_ip6_config (NMDnsManager *mgr, if (!g_slist_find (priv->configs, config)) priv->configs = g_slist_append (priv->configs, g_object_ref (config)); - if (!priv->updates_queue && !update_dns (mgr, FALSE, &error)) { - nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message); + if (!priv->updates_queue && !update_dns (self, FALSE, &error)) { + _LOGW ("could not commit DNS changes: %s", error->message); g_clear_error (&error); } @@ -945,15 +1151,15 @@ nm_dns_manager_add_ip6_config (NMDnsManager *mgr, } gboolean -nm_dns_manager_remove_ip6_config (NMDnsManager *mgr, NMIP6Config *config) +nm_dns_manager_remove_ip6_config (NMDnsManager *self, NMIP6Config *config) { NMDnsManagerPrivate *priv; GError *error = NULL; - g_return_val_if_fail (mgr != NULL, FALSE); + g_return_val_if_fail (self != NULL, FALSE); g_return_val_if_fail (config != NULL, FALSE); - priv = NM_DNS_MANAGER_GET_PRIVATE (mgr); + priv = NM_DNS_MANAGER_GET_PRIVATE (self); /* Can't remove it if it wasn't in the list to begin with */ if (!g_slist_find (priv->configs, config)) @@ -966,10 +1172,10 @@ nm_dns_manager_remove_ip6_config (NMDnsManager *mgr, NMIP6Config *config) if (config == priv->ip6_device_config) priv->ip6_device_config = NULL; - g_object_unref (config); + g_object_unref (config); - if (!priv->updates_queue && !update_dns (mgr, FALSE, &error)) { - nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message); + if (!priv->updates_queue && !update_dns (self, FALSE, &error)) { + _LOGW ("could not commit DNS changes: %s", error->message); g_clear_error (&error); } @@ -979,19 +1185,19 @@ nm_dns_manager_remove_ip6_config (NMDnsManager *mgr, NMIP6Config *config) } void -nm_dns_manager_set_initial_hostname (NMDnsManager *mgr, +nm_dns_manager_set_initial_hostname (NMDnsManager *self, const char *hostname) { - NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (mgr); + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); priv->hostname = g_strdup (hostname); } void -nm_dns_manager_set_hostname (NMDnsManager *mgr, +nm_dns_manager_set_hostname (NMDnsManager *self, const char *hostname) { - NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (mgr); + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); GError *error = NULL; const char *filtered = NULL; @@ -1010,25 +1216,25 @@ nm_dns_manager_set_hostname (NMDnsManager *mgr, g_free (priv->hostname); priv->hostname = g_strdup (filtered); - if (!priv->updates_queue && !update_dns (mgr, FALSE, &error)) { - nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message); + if (!priv->updates_queue && !update_dns (self, FALSE, &error)) { + _LOGW ("could not commit DNS changes: %s", error->message); g_clear_error (&error); } } NMDnsManagerResolvConfMode -nm_dns_manager_get_resolv_conf_mode (NMDnsManager *mgr) +nm_dns_manager_get_resolv_conf_mode (NMDnsManager *self) { - return NM_DNS_MANAGER_GET_PRIVATE (mgr)->resolv_conf_mode; + return NM_DNS_MANAGER_GET_PRIVATE (self)->resolv_conf_mode; } void -nm_dns_manager_begin_updates (NMDnsManager *mgr, const char *func) +nm_dns_manager_begin_updates (NMDnsManager *self, const char *func) { NMDnsManagerPrivate *priv; - g_return_if_fail (mgr != NULL); - priv = NM_DNS_MANAGER_GET_PRIVATE (mgr); + g_return_if_fail (self != NULL); + priv = NM_DNS_MANAGER_GET_PRIVATE (self); /* Save current hash when starting a new batch */ if (priv->updates_queue == 0) @@ -1036,36 +1242,36 @@ nm_dns_manager_begin_updates (NMDnsManager *mgr, const char *func) priv->updates_queue++; - nm_log_dbg (LOGD_DNS, "(%s): queueing DNS updates (%d)", func, priv->updates_queue); + _LOGD ("(%s): queueing DNS updates (%d)", func, priv->updates_queue); } void -nm_dns_manager_end_updates (NMDnsManager *mgr, const char *func) +nm_dns_manager_end_updates (NMDnsManager *self, const char *func) { NMDnsManagerPrivate *priv; GError *error = NULL; gboolean changed; guint8 new[HASH_LEN]; - g_return_if_fail (mgr != NULL); + g_return_if_fail (self != NULL); - priv = NM_DNS_MANAGER_GET_PRIVATE (mgr); + priv = NM_DNS_MANAGER_GET_PRIVATE (self); g_return_if_fail (priv->updates_queue > 0); - compute_hash (mgr, new); + compute_hash (self, nm_config_data_get_global_dns_config (nm_config_get_data (priv->config)), new); changed = (memcmp (new, priv->prev_hash, sizeof (new)) != 0) ? TRUE : FALSE; - nm_log_dbg (LOGD_DNS, "(%s): DNS configuration %s", __func__, changed ? "changed" : "did not change"); + _LOGD ("(%s): DNS configuration %s", func, changed ? "changed" : "did not change"); priv->updates_queue--; if ((priv->updates_queue > 0) || (changed == FALSE)) { - nm_log_dbg (LOGD_DNS, "(%s): no DNS changes to commit (%d)", func, priv->updates_queue); + _LOGD ("(%s): no DNS changes to commit (%d)", func, priv->updates_queue); return; } /* Commit all the outstanding changes */ - nm_log_dbg (LOGD_DNS, "(%s): committing DNS changes (%d)", func, priv->updates_queue); - if (!update_dns (mgr, FALSE, &error)) { - nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message); + _LOGD ("(%s): committing DNS changes (%d)", func, priv->updates_queue); + if (!update_dns (self, FALSE, &error)) { + _LOGW ("could not commit DNS changes: %s", error->message); g_clear_error (&error); } @@ -1085,6 +1291,12 @@ init_resolv_conf_mode (NMDnsManager *self) g_clear_object (&priv->plugin); + mode = nm_config_data_get_dns_mode (nm_config_get_data (priv->config)); + if (!g_strcmp0 (mode, "none")) { + priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED; + goto out; + } + fd = open (_PATH_RESCONF, O_RDONLY); if (fd != -1) { if (ioctl (fd, FS_IOC_GETFLAGS, &flags) == -1) @@ -1092,17 +1304,13 @@ init_resolv_conf_mode (NMDnsManager *self) close (fd); if (flags & FS_IMMUTABLE_FL) { - nm_log_info (LOGD_DNS, "DNS: " _PATH_RESCONF " is immutable; not managing"); + _LOGI ("set resolv-conf-mode: none -- " _PATH_RESCONF " is immutable"); priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED; return; } } - mode = nm_config_data_get_dns_mode (nm_config_get_data (priv->config)); - if (!g_strcmp0 (mode, "none")) { - priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED; - nm_log_info (LOGD_DNS, "DNS: not managing " _PATH_RESCONF); - } else if (!g_strcmp0 (mode, "dnsmasq")) { + if (!g_strcmp0 (mode, "dnsmasq")) { priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_PROXY; priv->plugin = nm_dns_dnsmasq_new (); } else if (!g_strcmp0 (mode, "unbound")) { @@ -1110,15 +1318,61 @@ init_resolv_conf_mode (NMDnsManager *self) priv->plugin = nm_dns_unbound_new (); } else { priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_EXPLICIT; - if (mode && g_strcmp0 (mode, "default") != 0) - nm_log_warn (LOGD_DNS, "Unknown DNS mode '%s'", mode); + if (mode && g_strcmp0 (mode, "default") != 0) { + _LOGW ("set resolve-conf-mode: default -- unknown configuration '%s'", mode); + return; + } + mode = "default"; } if (priv->plugin) { - nm_log_info (LOGD_DNS, "DNS: loaded plugin %s", nm_dns_plugin_get_name (priv->plugin)); g_signal_connect (priv->plugin, NM_DNS_PLUGIN_FAILED, G_CALLBACK (plugin_failed), self); g_signal_connect (priv->plugin, NM_DNS_PLUGIN_CHILD_QUIT, G_CALLBACK (plugin_child_quit), self); } + +out: + _LOGI ("set resolv-conf-mode: %s%s%s%s", mode, + NM_PRINT_FMT_QUOTED (priv->plugin, ", plugin=\"", nm_dns_plugin_get_name (priv->plugin), "\"", "")); +} + +static void +init_resolv_conf_manager (NMDnsManager *self) +{ + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); + const char *man, *desc = ""; + + man = nm_config_data_get_rc_manager (nm_config_get_data (priv->config)); + if (!g_strcmp0 (man, "none")) + priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE; + else if (!g_strcmp0 (man, "resolvconf")) + priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF; + else if (!g_strcmp0 (man, "netconfig")) + priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG; + else { +#if defined(RESOLVCONF_SELECTED) + priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF; +#elif defined(NETCONFIG_SELECTED) + priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG; +#else + priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE; +#endif + if (man) + _LOGW ("unknown resolv.conf manager '%s'", man); + } + + switch (priv->rc_manager) { + case NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF: + desc = "resolvconf"; + break; + case NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG: + desc = "netconfig"; + break; + case NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE: + desc = "none"; + break; + } + + _LOGI ("using resolv.conf manager '%s'", desc); } static void @@ -1132,12 +1386,16 @@ config_changed_cb (NMConfig *config, if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_DNS_MODE)) init_resolv_conf_mode (self); + if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_RC_MANAGER)) + init_resolv_conf_manager (self); if (NM_FLAGS_ANY (changes, NM_CONFIG_CHANGE_SIGHUP | NM_CONFIG_CHANGE_SIGUSR1 | - NM_CONFIG_CHANGE_DNS_MODE)) { + NM_CONFIG_CHANGE_DNS_MODE | + NM_CONFIG_CHANGE_RC_MANAGER | + NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG)) { if (!update_dns (self, TRUE, &error)) { - nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message); + _LOGW ("could not commit DNS changes: %s", error->message); g_clear_error (&error); } } @@ -1148,15 +1406,19 @@ nm_dns_manager_init (NMDnsManager *self) { NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); - /* Set the initial hash */ - compute_hash (self, NM_DNS_MANAGER_GET_PRIVATE (self)->hash); + _LOGT ("creating..."); priv->config = g_object_ref (nm_config_get ()); + /* Set the initial hash */ + compute_hash (self, nm_config_data_get_global_dns_config (nm_config_get_data (priv->config)), + NM_DNS_MANAGER_GET_PRIVATE (self)->hash); + g_signal_connect (G_OBJECT (priv->config), NM_CONFIG_SIGNAL_CONFIG_CHANGED, G_CALLBACK (config_changed_cb), self); init_resolv_conf_mode (self); + init_resolv_conf_manager (self); } static void @@ -1166,6 +1428,8 @@ dispose (GObject *object) NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); GError *error = NULL; + _LOGT ("disposing"); + if (priv->plugin) { g_signal_handlers_disconnect_by_func (priv->plugin, plugin_failed, self); g_signal_handlers_disconnect_by_func (priv->plugin, plugin_child_quit, self); @@ -1178,7 +1442,7 @@ dispose (GObject *object) * DNS updates yet, there's no reason to touch resolv.conf on shutdown. */ if (priv->dns_touched && !update_dns (self, TRUE, &error)) { - nm_log_warn (LOGD_DNS, "could not commit DNS changes on shutdown: %s", error->message); + _LOGW ("could not commit DNS changes on shutdown: %s", error->message); g_clear_error (&error); priv->dns_touched = FALSE; } diff --git a/src/dns-manager/nm-dns-manager.h b/src/dns-manager/nm-dns-manager.h index bc374fcf..7a55f1a2 100644 --- a/src/dns-manager/nm-dns-manager.h +++ b/src/dns-manager/nm-dns-manager.h @@ -24,7 +24,7 @@ #ifndef __NETWORKMANAGER_DNS_MANAGER_H__ #define __NETWORKMANAGER_DNS_MANAGER_H__ -#include +#include "nm-default.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" @@ -41,7 +41,7 @@ G_BEGIN_DECLS #define NM_DNS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NM_TYPE_DNS_MANAGER, NMDnsManagerClass)) #define NM_IS_DNS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NM_TYPE_DNS_MANAGER)) #define NM_IS_DNS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NM_TYPE_DNS_MANAGER)) -#define NM_DNS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NM_TYPE_DNS_MANAGER, NMDnsManagerClass)) +#define NM_DNS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NM_TYPE_DNS_MANAGER, NMDnsManagerClass)) typedef struct { GObject parent; @@ -59,26 +59,26 @@ GType nm_dns_manager_get_type (void); NMDnsManager * nm_dns_manager_get (void); /* Allow changes to be batched together */ -void nm_dns_manager_begin_updates (NMDnsManager *mgr, const char *func); -void nm_dns_manager_end_updates (NMDnsManager *mgr, const char *func); +void nm_dns_manager_begin_updates (NMDnsManager *self, const char *func); +void nm_dns_manager_end_updates (NMDnsManager *self, const char *func); -gboolean nm_dns_manager_add_ip4_config (NMDnsManager *mgr, +gboolean nm_dns_manager_add_ip4_config (NMDnsManager *self, const char *iface, NMIP4Config *config, NMDnsIPConfigType cfg_type); -gboolean nm_dns_manager_remove_ip4_config (NMDnsManager *mgr, NMIP4Config *config); +gboolean nm_dns_manager_remove_ip4_config (NMDnsManager *self, NMIP4Config *config); -gboolean nm_dns_manager_add_ip6_config (NMDnsManager *mgr, +gboolean nm_dns_manager_add_ip6_config (NMDnsManager *self, const char *iface, NMIP6Config *config, NMDnsIPConfigType cfg_type); -gboolean nm_dns_manager_remove_ip6_config (NMDnsManager *mgr, NMIP6Config *config); +gboolean nm_dns_manager_remove_ip6_config (NMDnsManager *self, NMIP6Config *config); -void nm_dns_manager_set_initial_hostname (NMDnsManager *mgr, +void nm_dns_manager_set_initial_hostname (NMDnsManager *self, const char *hostname); -void nm_dns_manager_set_hostname (NMDnsManager *mgr, +void nm_dns_manager_set_hostname (NMDnsManager *self, const char *hostname); /** @@ -99,7 +99,23 @@ typedef enum { NM_DNS_MANAGER_RESOLV_CONF_PROXY } NMDnsManagerResolvConfMode; -NMDnsManagerResolvConfMode nm_dns_manager_get_resolv_conf_mode (NMDnsManager *mgr); +/** + * NMDnsManagerResolvConfManager + * @NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE: NM directly writes resolv.conf + * @NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF: NM is managing resolv.conf + through resolvconf + * @NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG: NM is managing resolv.conf + through netconfig + * + * NMDnsManager's management of resolv.conf + */ +typedef enum { + NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE, + NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF, + NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG, +} NMDnsManagerResolvConfManager; + +NMDnsManagerResolvConfMode nm_dns_manager_get_resolv_conf_mode (NMDnsManager *self); G_END_DECLS diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c index 5b95d1c5..a8236696 100644 --- a/src/dns-manager/nm-dns-plugin.c +++ b/src/dns-manager/nm-dns-plugin.c @@ -24,10 +24,9 @@ #include #include #include -#include +#include "nm-default.h" #include "nm-dns-plugin.h" -#include "nm-logging.h" #include "NetworkManagerUtils.h" typedef struct { @@ -57,6 +56,7 @@ nm_dns_plugin_update (NMDnsPlugin *self, const GSList *vpn_configs, const GSList *dev_configs, const GSList *other_configs, + const NMGlobalDnsConfig *global_config, const char *hostname) { g_return_val_if_fail (NM_DNS_PLUGIN_GET_CLASS (self)->update != NULL, FALSE); @@ -65,6 +65,7 @@ nm_dns_plugin_update (NMDnsPlugin *self, vpn_configs, dev_configs, other_configs, + global_config, hostname); } @@ -188,10 +189,7 @@ nm_dns_plugin_child_kill (NMDnsPlugin *self) { NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self); - if (priv->watch_id) { - g_source_remove (priv->watch_id); - priv->watch_id = 0; - } + nm_clear_g_source (&priv->watch_id); if (priv->pid) { nm_utils_kill_child_sync (priv->pid, SIGTERM, LOGD_DNS, priv->progname, NULL, 1000, 0); diff --git a/src/dns-manager/nm-dns-plugin.h b/src/dns-manager/nm-dns-plugin.h index ee735a5a..7ecaa424 100644 --- a/src/dns-manager/nm-dns-plugin.h +++ b/src/dns-manager/nm-dns-plugin.h @@ -19,8 +19,9 @@ #ifndef __NETWORKMANAGER_DNS_PLUGIN_H__ #define __NETWORKMANAGER_DNS_PLUGIN_H__ -#include -#include +#include "nm-default.h" + +#include "nm-config-data.h" #define NM_TYPE_DNS_PLUGIN (nm_dns_plugin_get_type ()) #define NM_DNS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DNS_PLUGIN, NMDnsPlugin)) @@ -47,13 +48,15 @@ typedef struct { * NMIP4Config or NMIP6Config objects from VPN connections, while * 'dev_configs' is a list of NMPI4Config or NMIP6Config objects from * active devices. 'other_configs' represent other IP configuration that - * may be in-use. Configs of the same IP version are sorted in priority + * may be in-use. 'global_config' is the optional global DNS + * configuration. Configs of the same IP version are sorted in priority * order. */ gboolean (*update) (NMDnsPlugin *self, const GSList *vpn_configs, const GSList *dev_configs, const GSList *other_configs, + const NMGlobalDnsConfig *global_config, const char *hostname); /* Subclasses should override and return TRUE if they start a local @@ -92,6 +95,7 @@ gboolean nm_dns_plugin_update (NMDnsPlugin *self, const GSList *vpn_configs, const GSList *dev_configs, const GSList *other_configs, + const NMGlobalDnsConfig *global_config, const char *hostname); /* For subclasses/plugins */ diff --git a/src/dns-manager/nm-dns-unbound.c b/src/dns-manager/nm-dns-unbound.c index 5723bf82..d36e3f85 100644 --- a/src/dns-manager/nm-dns-unbound.c +++ b/src/dns-manager/nm-dns-unbound.c @@ -31,6 +31,7 @@ update (NMDnsPlugin *plugin, const GSList *vpn_configs, const GSList *dev_configs, const GSList *other_configs, + const NMGlobalDnsConfig *global_config, const char *hostname) { /* TODO: We currently call a script installed with the dnssec-trigger @@ -42,7 +43,7 @@ update (NMDnsPlugin *plugin, * without calling custom scripts. The dnssec-trigger functionality * may be eventually merged into NetworkManager. */ - return nm_spawn_process ("/usr/libexec/dnssec-trigger-script --async --update", NULL) == 0; + return nm_spawn_process (DNSSEC_TRIGGER_SCRIPT " --async --update", NULL) == 0; } static gboolean diff --git a/src/dns-manager/nm-dns-unbound.h b/src/dns-manager/nm-dns-unbound.h index 261326b2..abc056b9 100644 --- a/src/dns-manager/nm-dns-unbound.h +++ b/src/dns-manager/nm-dns-unbound.h @@ -18,8 +18,6 @@ #ifndef __NETWORKMANAGER_DNS_UNBOUND_H__ #define __NETWORKMANAGER_DNS_UNBOUND_H__ -#include - #include "nm-dns-plugin.h" #define NM_TYPE_DNS_UNBOUND (nm_dns_unbound_get_type ()) diff --git a/src/dnsmasq-manager/nm-dnsmasq-manager.c b/src/dnsmasq-manager/nm-dnsmasq-manager.c index 0cc698d9..a17caad3 100644 --- a/src/dnsmasq-manager/nm-dnsmasq-manager.c +++ b/src/dnsmasq-manager/nm-dnsmasq-manager.c @@ -28,10 +28,9 @@ #include #include +#include "nm-default.h" #include "nm-dnsmasq-manager.h" #include "nm-dnsmasq-utils.h" -#include "nm-logging.h" -#include "nm-glib-compat.h" #include "nm-utils.h" #include "NetworkManagerUtils.h" @@ -83,14 +82,14 @@ nm_dnsmasq_manager_class_init (NMDnsMasqManagerClass *manager_class) /* signals */ signals[STATE_CHANGED] = - g_signal_new ("state-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMDnsMasqManagerClass, state_changed), - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, - G_TYPE_UINT); + g_signal_new (NM_DNS_MASQ_MANAGER_STATE_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMDnsMasqManagerClass, state_changed), + NULL, NULL, + g_cclosure_marshal_VOID__UINT, + G_TYPE_NONE, 1, + G_TYPE_UINT); } NMDnsMasqManager * @@ -103,7 +102,7 @@ nm_dnsmasq_manager_new (const char *iface) priv = NM_DNSMASQ_MANAGER_GET_PRIVATE (manager); priv->iface = g_strdup (iface); - priv->pidfile = g_strdup_printf (LOCALSTATEDIR "/run/nm-dnsmasq-%s.pid", iface); + priv->pidfile = g_strdup_printf (RUNSTATEDIR "/nm-dnsmasq-%s.pid", iface); return manager; } @@ -386,10 +385,7 @@ nm_dnsmasq_manager_stop (NMDnsMasqManager *manager) priv = NM_DNSMASQ_MANAGER_GET_PRIVATE (manager); - if (priv->dm_watch_id) { - g_source_remove (priv->dm_watch_id); - priv->dm_watch_id = 0; - } + nm_clear_g_source (&priv->dm_watch_id); if (priv->pid) { nm_utils_kill_child_async (priv->pid, SIGTERM, LOGD_SHARING, "dnsmasq", 2000, NULL, NULL); diff --git a/src/dnsmasq-manager/nm-dnsmasq-manager.h b/src/dnsmasq-manager/nm-dnsmasq-manager.h index 257cc755..47c88e6e 100644 --- a/src/dnsmasq-manager/nm-dnsmasq-manager.h +++ b/src/dnsmasq-manager/nm-dnsmasq-manager.h @@ -21,9 +21,8 @@ #ifndef __NETWORKMANAGER_DNSMASQ_MANAGER_H__ #define __NETWORKMANAGER_DNSMASQ_MANAGER_H__ -#include -#include +#include "nm-default.h" #include "nm-ip4-config.h" #define NM_TYPE_DNSMASQ_MANAGER (nm_dnsmasq_manager_get_type ()) @@ -33,6 +32,9 @@ #define NM_IS_DNSMASQ_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DNSMASQ_MANAGER)) #define NM_DNSMASQ_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DNSMASQ_MANAGER, NMDnsMasqManagerClass)) +/* signals */ +#define NM_DNS_MASQ_MANAGER_STATE_CHANGED "state-changed" + typedef enum { NM_DNSMASQ_STATUS_UNKNOWN, diff --git a/src/dnsmasq-manager/nm-dnsmasq-utils.h b/src/dnsmasq-manager/nm-dnsmasq-utils.h index bb468c82..43d0b9a3 100644 --- a/src/dnsmasq-manager/nm-dnsmasq-utils.h +++ b/src/dnsmasq-manager/nm-dnsmasq-utils.h @@ -21,7 +21,7 @@ #ifndef __NETWORKMANAGER_DNSMASQ_UTILS_H__ #define __NETWORKMANAGER_DNSMASQ_UTILS_H__ -#include +#include "nm-default.h" #include "nm-platform.h" gboolean nm_dnsmasq_utils_get_range (const NMPlatformIP4Address *addr, diff --git a/src/dnsmasq-manager/tests/Makefile.am b/src/dnsmasq-manager/tests/Makefile.am index e9200007..2c5e8e40 100644 --- a/src/dnsmasq-manager/tests/Makefile.am +++ b/src/dnsmasq-manager/tests/Makefile.am @@ -1,13 +1,13 @@ AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I${top_builddir}/include \ + -I$(top_srcdir)/shared \ + -I${top_builddir}/shared \ -I${top_srcdir}/libnm-core \ -I${top_builddir}/libnm-core \ -I$(top_srcdir)/src/dnsmasq-manager \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/platform \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ -DTESTDIR="\"$(abs_srcdir)\"" diff --git a/src/dnsmasq-manager/tests/Makefile.in b/src/dnsmasq-manager/tests/Makefile.in index fb2cd1d1..ff97e120 100644 --- a/src/dnsmasq-manager/tests/Makefile.in +++ b/src/dnsmasq-manager/tests/Makefile.in @@ -403,7 +403,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -415,8 +414,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -426,6 +423,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -480,16 +478,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -526,6 +521,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -554,7 +551,6 @@ 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@ @@ -569,6 +565,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -629,6 +627,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -636,6 +635,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -652,15 +652,15 @@ with_netconfig = @with_netconfig@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I${top_builddir}/include \ + -I$(top_srcdir)/shared \ + -I${top_builddir}/shared \ -I${top_srcdir}/libnm-core \ -I${top_builddir}/libnm-core \ -I$(top_srcdir)/src/dnsmasq-manager \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/platform \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ -DTESTDIR="\"$(abs_srcdir)\"" diff --git a/src/dnsmasq-manager/tests/test-dnsmasq-utils.c b/src/dnsmasq-manager/tests/test-dnsmasq-utils.c index f8120ffe..04bf1b4d 100644 --- a/src/dnsmasq-manager/tests/test-dnsmasq-utils.c +++ b/src/dnsmasq-manager/tests/test-dnsmasq-utils.c @@ -20,18 +20,19 @@ #include "config.h" -#include #include +#include "nm-default.h" #include "nm-dnsmasq-utils.h" -static guint32 -addr_to_num (const char *addr) -{ - guint n; +#include "nm-test-utils.h" - g_assert (inet_pton (AF_INET, addr, (void *) &n) == 1); - return n; +static NMPlatformIP4Address * +_set_addr (NMPlatformIP4Address *addr, const char *address, int plen) +{ + memset (addr, 0, sizeof (*addr)); + nm_platform_ip4_address_set_addr (addr, nmtst_inet4_from_string (address), plen); + return addr; } static void @@ -42,58 +43,50 @@ test_address_ranges (void) char last[INET_ADDRSTRLEN]; char *error_desc = NULL; - addr.address = addr_to_num ("192.168.0.1"); - addr.plen = 24; + _set_addr (&addr, "192.168.0.1", 24); g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc)); g_assert (error_desc == NULL); g_assert_cmpstr (first, ==, "192.168.0.10"); g_assert_cmpstr (last, ==, "192.168.0.254"); - addr.address = addr_to_num ("192.168.0.99"); - addr.plen = 24; + _set_addr (&addr, "192.168.0.99", 24); g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc)); g_assert (error_desc == NULL); g_assert_cmpstr (first, ==, "192.168.0.108"); g_assert_cmpstr (last, ==, "192.168.0.254"); - addr.address = addr_to_num ("192.168.0.254"); - addr.plen = 24; + _set_addr (&addr, "192.168.0.254", 24); g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc)); g_assert (error_desc == NULL); g_assert_cmpstr (first, ==, "192.168.0.1"); g_assert_cmpstr (last, ==, "192.168.0.245"); /* Smaller networks */ - addr.address = addr_to_num ("1.2.3.1"); - addr.plen = 30; + _set_addr (&addr, "1.2.3.1", 30); g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc)); g_assert (error_desc == NULL); g_assert_cmpstr (first, ==, "1.2.3.2"); g_assert_cmpstr (last, ==, "1.2.3.2"); - addr.address = addr_to_num ("1.2.3.1"); - addr.plen = 29; + _set_addr (&addr, "1.2.3.1", 29); g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc)); g_assert (error_desc == NULL); g_assert_cmpstr (first, ==, "1.2.3.2"); g_assert_cmpstr (last, ==, "1.2.3.6"); - addr.address = addr_to_num ("1.2.3.1"); - addr.plen = 28; + _set_addr (&addr, "1.2.3.1", 28); g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc)); g_assert (error_desc == NULL); g_assert_cmpstr (first, ==, "1.2.3.3"); g_assert_cmpstr (last, ==, "1.2.3.14"); - addr.address = addr_to_num ("1.2.3.1"); - addr.plen = 26; + _set_addr (&addr, "1.2.3.1", 26); g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc)); g_assert (error_desc == NULL); g_assert_cmpstr (first, ==, "1.2.3.8"); g_assert_cmpstr (last, ==, "1.2.3.62"); - addr.address = addr_to_num ("1.2.3.1"); - addr.plen = 31; + _set_addr (&addr, "1.2.3.1", 31); g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc) == FALSE); g_assert (error_desc); g_free (error_desc); @@ -101,14 +94,12 @@ test_address_ranges (void) /*******************************************/ +NMTST_DEFINE (); + int main (int argc, char **argv) { - g_test_init (&argc, &argv, NULL); - -#if !GLIB_CHECK_VERSION (2, 35, 0) - g_type_init (); -#endif + nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); g_test_add_func ("/dnsmasq-manager/address-ranges", test_address_ranges); diff --git a/src/main-utils.c b/src/main-utils.c index da327c40..7425d0bc 100644 --- a/src/main-utils.c +++ b/src/main-utils.c @@ -29,17 +29,12 @@ #include #include -#include -#include #include #include -#include "nm-glib-compat.h" - -#include "gsystem-local-alloc.h" +#include "nm-default.h" #include "main-utils.h" #include "NetworkManagerUtils.h" -#include "nm-logging.h" static gboolean sighup_handler (gpointer user_data) diff --git a/src/main-utils.h b/src/main-utils.h index 49550295..cae97b57 100644 --- a/src/main-utils.h +++ b/src/main-utils.h @@ -21,7 +21,7 @@ #ifndef __MAIN_UTILS_H__ #define __MAIN_UTILS_H__ -#include +#include "nm-default.h" void nm_main_utils_ensure_root (void); diff --git a/src/main.c b/src/main.c index 2de36dc1..ee8e0f2d 100644 --- a/src/main.c +++ b/src/main.c @@ -21,10 +21,6 @@ #include "config.h" -#include -#include -#include -#include #include #include #include @@ -35,27 +31,26 @@ #include #include #include -#include #include #include #include -#include "gsystem-local-alloc.h" +#include "nm-default.h" #include "nm-dbus-interface.h" #include "NetworkManagerUtils.h" #include "main-utils.h" #include "nm-manager.h" #include "nm-linux-platform.h" -#include "nm-dbus-manager.h" +#include "nm-bus-manager.h" #include "nm-device.h" #include "nm-dhcp-manager.h" -#include "nm-logging.h" #include "nm-config.h" #include "nm-session-monitor.h" #include "nm-dispatcher.h" #include "nm-settings.h" #include "nm-auth-manager.h" #include "nm-core-internal.h" +#include "nm-exported-object.h" #if !defined(NM_DIST_VERSION) # define NM_DIST_VERSION VERSION @@ -71,7 +66,6 @@ static struct { gboolean show_version; gboolean print_config; gboolean become_daemon; - gboolean debug; gboolean g_fatal_warnings; gboolean run_from_build_dir; char *opt_log_level; @@ -87,17 +81,15 @@ parse_state_file (const char *filename, gboolean *net_enabled, gboolean *wifi_enabled, gboolean *wwan_enabled, - gboolean *wimax_enabled, GError **error) { GKeyFile *state_file; GError *tmp_error = NULL; - gboolean wifi, net, wwan, wimax; + gboolean wifi, net, wwan; g_return_val_if_fail (net_enabled != NULL, FALSE); g_return_val_if_fail (wifi_enabled != NULL, FALSE); g_return_val_if_fail (wwan_enabled != NULL, FALSE); - g_return_val_if_fail (wimax_enabled != NULL, FALSE); state_file = g_key_file_new (); g_key_file_set_list_separator (state_file, ','); @@ -119,7 +111,6 @@ parse_state_file (const char *filename, g_key_file_set_boolean (state_file, "main", "NetworkingEnabled", *net_enabled); g_key_file_set_boolean (state_file, "main", "WirelessEnabled", *wifi_enabled); g_key_file_set_boolean (state_file, "main", "WWANEnabled", *wwan_enabled); - g_key_file_set_boolean (state_file, "main", "WimaxEnabled", *wimax_enabled); data = g_key_file_to_data (state_file, &len, NULL); if (data) @@ -151,11 +142,6 @@ parse_state_file (const char *filename, *wwan_enabled = wwan; g_clear_error (&tmp_error); - wimax = g_key_file_get_boolean (state_file, "main", "WimaxEnabled", &tmp_error); - if (tmp_error == NULL) - *wimax_enabled = wimax; - g_clear_error (&tmp_error); - g_key_file_free (state_file); return TRUE; } @@ -235,7 +221,7 @@ print_config (NMConfigCmdLineOptions *config_cli) nm_logging_setup ("OFF", "ALL", NULL, NULL); - config = nm_config_new (config_cli, &error); + config = nm_config_new (config_cli, NULL, &error); if (config == NULL) { fprintf (stderr, _("Failed to read configuration: %s\n"), (error && error->message) ? error->message : _("unknown")); @@ -254,7 +240,6 @@ do_early_setup (int *argc, char **argv[], NMConfigCmdLineOptions *config_cli) GOptionEntry options[] = { { "version", 'V', 0, G_OPTION_ARG_NONE, &global_opt.show_version, N_("Print NetworkManager version and exit"), NULL }, { "no-daemon", 'n', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &global_opt.become_daemon, N_("Don't become a daemon"), NULL }, - { "debug", 'd', 0, G_OPTION_ARG_NONE, &global_opt.debug, N_("Don't become a daemon, and log to stderr"), NULL }, { "log-level", 0, 0, G_OPTION_ARG_STRING, &global_opt.opt_log_level, N_("Log level: one of [%s]"), "INFO" }, { "log-domains", 0, 0, G_OPTION_ARG_STRING, &global_opt.opt_log_domains, N_("Log domains separated by ',': any combination of [%s]"), @@ -287,20 +272,21 @@ do_early_setup (int *argc, char **argv[], NMConfigCmdLineOptions *config_cli) int main (int argc, char *argv[]) { - gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE, wimax_enabled = TRUE; + gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE; gboolean success = FALSE; - NMManager *manager = NULL; - gs_unref_object NMSettings *settings = NULL; - gs_unref_object NMConfig *config = NULL; - gs_unref_object NMSessionMonitor *session_monitor = NULL; + NMConfig *config; GError *error = NULL; gboolean wrote_pidfile = FALSE; char *bad_domains = NULL; NMConfigCmdLineOptions *config_cli; -#if !GLIB_CHECK_VERSION (2, 35, 0) - g_type_init (); -#endif + nm_g_type_init (); + + /* Known to cause a possible deadlock upon GDBus initialization: + * https://bugzilla.gnome.org/show_bug.cgi?id=674885 */ + g_type_ensure (G_TYPE_SOCKET); + g_type_ensure (G_TYPE_DBUS_CONNECTION); + g_type_ensure (NM_TYPE_BUS_MANAGER); _nm_utils_is_manager_process = TRUE; @@ -356,7 +342,6 @@ main (int argc, char *argv[]) /* don't free these strings, we need them for the entire * process lifetime */ nm_dhcp_helper_path = g_strdup_printf ("%s/src/dhcp-manager/nm-dhcp-helper", path); - nm_device_autoipd_helper_path = g_strdup_printf ("%s/callouts/nm-avahi-autoipd.action", path); g_free (path); } @@ -377,7 +362,7 @@ main (int argc, char *argv[]) } /* Read the config file and CLI overrides */ - config = nm_config_setup (config_cli, &error); + config = nm_config_setup (config_cli, NULL, &error); nm_config_cmd_line_options_free (config_cli); config_cli = NULL; if (config == NULL) { @@ -408,7 +393,7 @@ main (int argc, char *argv[]) } } - if (global_opt.become_daemon && !global_opt.debug) { + if (global_opt.become_daemon && !nm_config_get_is_debug (config)) { if (daemon (0, 0) < 0) { int saved_errno; @@ -424,12 +409,17 @@ main (int argc, char *argv[]) /* Set up unix signal handling - before creating threads, but after daemonizing! */ nm_main_utils_setup_signals (main_loop); - nm_logging_syslog_openlog (global_opt.debug); + nm_logging_syslog_openlog (nm_config_get_is_debug (config) + ? "debug" + : nm_config_data_get_value_cached (NM_CONFIG_GET_DATA_ORIG, + NM_CONFIG_KEYFILE_GROUP_LOGGING, + NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND, + NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY)); nm_log_info (LOGD_CORE, "NetworkManager (version " NM_DIST_VERSION ") is starting..."); /* Parse the state file */ - if (!parse_state_file (global_opt.state_file, &net_enabled, &wifi_enabled, &wwan_enabled, &wimax_enabled, &error)) { + if (!parse_state_file (global_opt.state_file, &net_enabled, &wifi_enabled, &wwan_enabled, &error)) { nm_log_err (LOGD_CORE, "State file %s parsing failed: (%d) %s", global_opt.state_file, error ? error->code : -1, @@ -438,13 +428,6 @@ main (int argc, char *argv[]) } g_clear_error (&error); - dbus_threads_init_default (); - - /* Ensure that non-exported properties don't leak out, and that the - * introspection 'access' permissions are respected. - */ - dbus_glib_global_set_disable_legacy_property_access (); - nm_log_info (LOGD_CORE, "Read config: %s", nm_config_data_get_config_description (nm_config_get_data (config))); nm_config_data_log (nm_config_get_data (config), "CONFIG: ", " ", NULL); nm_log_dbg (LOGD_CORE, "WEXT support is %s", @@ -455,16 +438,18 @@ main (int argc, char *argv[]) #endif ); - if (!nm_dbus_manager_get_connection (nm_dbus_manager_get ())) { -#if HAVE_DBUS_GLIB_100 + nm_auth_manager_setup (nm_config_get_auth_polkit (config)); + + nm_manager_setup (global_opt.state_file, + net_enabled, + wifi_enabled, + wwan_enabled); + + if (!nm_bus_manager_get_connection (nm_bus_manager_get ())) { nm_log_warn (LOGD_CORE, "Failed to connect to D-Bus; only private bus is available"); -#else - nm_log_err (LOGD_CORE, "Failed to connect to D-Bus, exiting..."); - goto done; -#endif } else { /* Start our DBus service */ - if (!nm_dbus_manager_start_service (nm_dbus_manager_get ())) { + if (!nm_bus_manager_start_service (nm_bus_manager_get ())) { nm_log_err (LOGD_CORE, "failed to start the dbus service."); goto done; } @@ -473,32 +458,17 @@ main (int argc, char *argv[]) /* Set up platform interaction layer */ nm_linux_platform_setup (); - nm_auth_manager_setup (nm_config_get_auth_polkit (config)); + NM_UTILS_KEEP_ALIVE (config, NM_PLATFORM_GET, "NMConfig-depends-on-NMPlatform"); nm_dispatcher_init (); - settings = nm_settings_new (&error); - if (!settings) { - nm_log_err (LOGD_CORE, "failed to initialize settings storage: %s", - error && error->message ? error->message : "(unknown)"); + g_signal_connect (nm_manager_get (), NM_MANAGER_CONFIGURE_QUIT, G_CALLBACK (manager_configure_quit), config); + + if (!nm_manager_start (nm_manager_get (), &error)) { + nm_log_err (LOGD_CORE, "failed to initialize: %s", error->message); goto done; } - manager = nm_manager_new (settings, - global_opt.state_file, - net_enabled, - wifi_enabled, - wwan_enabled, - wimax_enabled); - - /* Initialize session monitor */ - session_monitor = nm_session_monitor_get (); - g_assert (session_monitor != NULL); - - g_signal_connect (manager, NM_MANAGER_CONFIGURE_QUIT, G_CALLBACK (manager_configure_quit), config); - - nm_manager_start (manager); - /* Make sure the loopback interface is up. If interface is down, we bring * it up and kernel will assign it link-local IPv4 and IPv6 addresses. If * it was already up, we assume is in clean state. @@ -517,12 +487,10 @@ main (int argc, char *argv[]) if (configure_and_quit == FALSE) g_main_loop_run (main_loop); - nm_manager_stop (manager); - done: - g_clear_object (&manager); + nm_exported_object_class_set_quitting (); - nm_logging_syslog_closelog (); + nm_manager_stop (nm_manager_get ()); if (global_opt.pidfile && wrote_pidfile) unlink (global_opt.pidfile); diff --git a/src/nm-access-point-glue.h b/src/nm-access-point-glue.h deleted file mode 100644 index 39b22cc2..00000000 --- a/src/nm-access-point-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_access_point_MARSHAL_H__ -#define __dbus_glib_marshal_nm_access_point_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_access_point_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_access_point_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_access_point_object_info = { 1, - dbus_glib_nm_access_point_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.AccessPoint\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.AccessPoint\0Flags\0flags\0read\0org.freedesktop.NetworkManager.AccessPoint\0WpaFlags\0wpa_flags\0read\0org.freedesktop.NetworkManager.AccessPoint\0RsnFlags\0rsn_flags\0read\0org.freedesktop.NetworkManager.AccessPoint\0Ssid\0ssid\0read\0org.freedesktop.NetworkManager.AccessPoint\0Frequency\0frequency\0read\0org.freedesktop.NetworkManager.AccessPoint\0HwAddress\0hw_address\0read\0org.freedesktop.NetworkManager.AccessPoint\0Mode\0mode\0read\0org.freedesktop.NetworkManager.AccessPoint\0MaxBitrate\0max_bitrate\0read\0org.freedesktop.NetworkManager.AccessPoint\0Strength\0strength\0read\0org.freedesktop.NetworkManager.AccessPoint\0LastSeen\0last_seen\0read\0\0" -}; - diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c index 2c084b87..30e98fca 100644 --- a/src/nm-activation-request.c +++ b/src/nm-activation-request.c @@ -26,10 +26,9 @@ #include #include -#include "gsystem-local-alloc.h" #include "nm-activation-request.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-setting-wireless-security.h" #include "nm-setting-8021x.h" #include "nm-device.h" @@ -66,42 +65,101 @@ enum { /*******************************************************************/ +NMSettingsConnection * +nm_act_request_get_settings_connection (NMActRequest *req) +{ + g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NULL); + + return nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (req)); +} + NMConnection * -nm_act_request_get_connection (NMActRequest *req) +nm_act_request_get_applied_connection (NMActRequest *req) { g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NULL); - return nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (req)); + return nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (req)); } /*******************************************************************/ -typedef struct { +struct _NMActRequestGetSecretsCallId { NMActRequest *self; - guint32 call_id; NMActRequestSecretsFunc callback; gpointer callback_data; -} GetSecretsInfo; + NMSettingsConnectionCallId call_id; +}; + +typedef struct _NMActRequestGetSecretsCallId GetSecretsInfo; + +static GetSecretsInfo * +_get_secrets_info_new (NMActRequest *self, NMActRequestSecretsFunc callback, gpointer callback_data) +{ + GetSecretsInfo *info; + + info = g_slice_new0 (GetSecretsInfo); + info->self = self; + info->callback = callback; + info->callback_data = callback_data; + + return info; +} + +static void +_get_secrets_info_free (GetSecretsInfo *info) +{ + g_slice_free (GetSecretsInfo, info); +} static void get_secrets_cb (NMSettingsConnection *connection, - guint32 call_id, + NMSettingsConnectionCallId call_id_s, const char *agent_username, const char *setting_name, GError *error, gpointer user_data) { GetSecretsInfo *info = user_data; - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (info->self); + NMActRequestPrivate *priv; + + g_return_if_fail (info && info->call_id == call_id_s); + g_return_if_fail (NM_IS_ACT_REQUEST (info->self)); + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + priv = NM_ACT_REQUEST_GET_PRIVATE (info->self); + + g_return_if_fail (g_slist_find (priv->secrets_calls, info)); - g_return_if_fail (info->call_id == call_id); priv->secrets_calls = g_slist_remove (priv->secrets_calls, info); - info->callback (info->self, call_id, NM_CONNECTION (connection), error, info->callback_data); - g_free (info); + if (info->callback) + info->callback (info->self, info, connection, error, info->callback_data); + + _get_secrets_info_free (info); } -guint32 +/** + * nm_act_request_get_secrets: + * @self: + * @setting_name: + * @flags: + * @hint: + * @callback: + * @callback_data: + * + * Asnychronously starts the request for secrets. This function cannot + * fail. + * + * The return call-id can be used to cancel the request. You are + * only allowed to cancel a still pending operation (once). + * The callback will always be invoked once, even for canceling + * or disposing of NMActRequest. + * + * Returns: a call-id. + */ +NMActRequestGetSecretsCallId nm_act_request_get_secrets (NMActRequest *self, const char *setting_name, NMSecretAgentGetSecretsFlags flags, @@ -111,68 +169,82 @@ nm_act_request_get_secrets (NMActRequest *self, { NMActRequestPrivate *priv; GetSecretsInfo *info; - guint32 call_id; - NMConnection *connection; + NMSettingsConnectionCallId call_id_s; + NMSettingsConnection *settings_connection; + NMConnection *applied_connection; const char *hints[2] = { hint, NULL }; - g_return_val_if_fail (self, 0); g_return_val_if_fail (NM_IS_ACT_REQUEST (self), 0); priv = NM_ACT_REQUEST_GET_PRIVATE (self); - info = g_malloc0 (sizeof (GetSecretsInfo)); - info->self = self; - info->callback = callback; - info->callback_data = callback_data; + settings_connection = nm_act_request_get_settings_connection (self); + applied_connection = nm_act_request_get_applied_connection (self); + + info = _get_secrets_info_new (self, callback, callback_data); + + priv->secrets_calls = g_slist_append (priv->secrets_calls, info); if (nm_active_connection_get_user_requested (NM_ACTIVE_CONNECTION (self))) flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED; - connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (self)); - call_id = nm_settings_connection_get_secrets (NM_SETTINGS_CONNECTION (connection), - nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (self)), - setting_name, - flags, - hints, - get_secrets_cb, - info, - NULL); - if (call_id > 0) { - info->call_id = call_id; - priv->secrets_calls = g_slist_append (priv->secrets_calls, info); - } else - g_free (info); - - return call_id; + call_id_s = nm_settings_connection_get_secrets (settings_connection, + applied_connection, + nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (self)), + setting_name, + flags, + hints, + get_secrets_cb, + info); + info->call_id = call_id_s; + g_return_val_if_fail (call_id_s, NULL); + return info; +} + +static void +_do_cancel_secrets (NMActRequest *self, GetSecretsInfo *info, gboolean is_disposing) +{ + NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self); + + nm_assert (info && info->self == self); + nm_assert (g_slist_find (priv->secrets_calls, info)); + + priv->secrets_calls = g_slist_remove (priv->secrets_calls, info); + + nm_settings_connection_cancel_secrets (nm_act_request_get_settings_connection (self), info->call_id); + + if (info->callback) { + gs_free_error GError *error = NULL; + + nm_utils_error_set_cancelled (&error, is_disposing, "NMActRequest"); + info->callback (self, info, NULL, error, info->callback_data); + } + + _get_secrets_info_free (info); } void -nm_act_request_cancel_secrets (NMActRequest *self, guint32 call_id) +nm_act_request_cancel_secrets (NMActRequest *self, NMActRequestGetSecretsCallId call_id) { NMActRequestPrivate *priv; - NMConnection *connection; - GSList *iter; - g_return_if_fail (self); g_return_if_fail (NM_IS_ACT_REQUEST (self)); - g_return_if_fail (call_id > 0); + g_return_if_fail (call_id); priv = NM_ACT_REQUEST_GET_PRIVATE (self); - connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (self)); - for (iter = priv->secrets_calls; iter; iter = g_slist_next (iter)) { - GetSecretsInfo *info = iter->data; + if (!g_slist_find (priv->secrets_calls, call_id)) + g_return_if_reached (); - /* Remove the matching info */ - if (info->call_id == call_id) { - priv->secrets_calls = g_slist_remove_link (priv->secrets_calls, iter); - g_slist_free (iter); + _do_cancel_secrets (self, call_id, FALSE); +} - nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (connection), call_id); - g_free (info); - break; - } - } +void +nm_act_request_clear_secrets (NMActRequest *self) +{ + g_return_if_fail (NM_IS_ACT_REQUEST (self)); + + nm_active_connection_clear_secrets ((NMActiveConnection *) self); } /********************************************************************/ @@ -392,30 +464,28 @@ master_failed (NMActiveConnection *self) /** * nm_act_request_new: * - * @connection: the connection to activate @device with + * @settings_connection: (allow-none): the connection to activate @device with * @specific_object: the object path of the specific object (ie, WiFi access point, * etc) that will be used to activate @connection and @device * @subject: the #NMAuthSubject representing the requestor of the activation - * @device: the device/interface to configure according to @connection; or %NULL - * if the connection describes a software device which will be created during - * connection activation + * @device: the device/interface to configure according to @connection * * Creates a new device-based activation request. * * Returns: the new activation request on success, %NULL on error. */ NMActRequest * -nm_act_request_new (NMConnection *connection, +nm_act_request_new (NMSettingsConnection *settings_connection, const char *specific_object, NMAuthSubject *subject, NMDevice *device) { - g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - g_return_val_if_fail (!device || NM_IS_DEVICE (device), NULL); + g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); + g_return_val_if_fail (NM_IS_DEVICE (device), NULL); g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); return (NMActRequest *) g_object_new (NM_TYPE_ACT_REQUEST, - NM_ACTIVE_CONNECTION_INT_CONNECTION, connection, + NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION, settings_connection, NM_ACTIVE_CONNECTION_INT_DEVICE, device, NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object, NM_ACTIVE_CONNECTION_INT_SUBJECT, subject, @@ -430,9 +500,12 @@ nm_act_request_init (NMActRequest *req) static void dispose (GObject *object) { - NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object); - NMConnection *connection; - GSList *iter; + NMActRequest *self = NM_ACT_REQUEST (object); + NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self); + + /* Kill any in-progress secrets requests */ + while (priv->secrets_calls) + _do_cancel_secrets (self, priv->secrets_calls->data, TRUE); /* Clear any share rules */ if (priv->share_rules) { @@ -440,17 +513,6 @@ dispose (GObject *object) clear_share_rules (NM_ACT_REQUEST (object)); } - /* Kill any in-progress secrets requests */ - connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (object)); - for (iter = priv->secrets_calls; connection && iter; iter = g_slist_next (iter)) { - GetSecretsInfo *info = iter->data; - - nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (connection), info->call_id); - g_free (info); - } - g_slist_free (priv->secrets_calls); - priv->secrets_calls = NULL; - G_OBJECT_CLASS (nm_act_request_parent_class)->dispose (object); } @@ -462,7 +524,7 @@ get_property (GObject *object, guint prop_id, device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object)); if (!device) { - g_value_set_boxed (value, "/"); + g_value_set_string (value, "/"); return; } diff --git a/src/nm-activation-request.h b/src/nm-activation-request.h index 69756069..929ce195 100644 --- a/src/nm-activation-request.h +++ b/src/nm-activation-request.h @@ -21,10 +21,8 @@ #ifndef __NETWORKMANAGER_ACTIVATION_REQUEST_H__ #define __NETWORKMANAGER_ACTIVATION_REQUEST_H__ -#include -#include -#include "nm-types.h" +#include "nm-default.h" #include "nm-connection.h" #include "nm-active-connection.h" @@ -35,6 +33,9 @@ #define NM_IS_ACT_REQUEST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_ACT_REQUEST)) #define NM_ACT_REQUEST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ACT_REQUEST, NMActRequestClass)) +struct _NMActRequestGetSecretsCallId; +typedef struct _NMActRequestGetSecretsCallId *NMActRequestGetSecretsCallId; + struct _NMActRequest { NMActiveConnection parent; }; @@ -46,37 +47,40 @@ typedef struct { GType nm_act_request_get_type (void); -NMActRequest *nm_act_request_new (NMConnection *connection, +NMActRequest *nm_act_request_new (NMSettingsConnection *settings_connection, const char *specific_object, NMAuthSubject *subject, NMDevice *device); -NMConnection *nm_act_request_get_connection (NMActRequest *req); +NMSettingsConnection *nm_act_request_get_settings_connection (NMActRequest *req); + +NMConnection *nm_act_request_get_applied_connection (NMActRequest *req); -gboolean nm_act_request_get_shared (NMActRequest *req); +gboolean nm_act_request_get_shared (NMActRequest *req); -void nm_act_request_set_shared (NMActRequest *req, gboolean shared); +void nm_act_request_set_shared (NMActRequest *req, gboolean shared); -void nm_act_request_add_share_rule (NMActRequest *req, - const char *table, - const char *rule); +void nm_act_request_add_share_rule (NMActRequest *req, + const char *table, + const char *rule); /* Secrets handling */ typedef void (*NMActRequestSecretsFunc) (NMActRequest *req, - guint32 call_id, - NMConnection *connection, + NMActRequestGetSecretsCallId call_id, + NMSettingsConnection *connection, GError *error, gpointer user_data); -guint32 nm_act_request_get_secrets (NMActRequest *req, - const char *setting_name, - NMSecretAgentGetSecretsFlags flags, - const char *hint, - NMActRequestSecretsFunc callback, - gpointer callback_data); +NMActRequestGetSecretsCallId nm_act_request_get_secrets (NMActRequest *req, + const char *setting_name, + NMSecretAgentGetSecretsFlags flags, + const char *hint, + NMActRequestSecretsFunc callback, + gpointer callback_data); -void nm_act_request_cancel_secrets (NMActRequest *req, guint32 call_id); +void nm_act_request_cancel_secrets (NMActRequest *req, NMActRequestGetSecretsCallId call_id); +void nm_act_request_clear_secrets (NMActRequest *self); #endif /* __NETWORKMANAGER_ACTIVATION_REQUEST_H__ */ diff --git a/src/nm-active-connection-glue.h b/src/nm-active-connection-glue.h deleted file mode 100644 index 9076e186..00000000 --- a/src/nm-active-connection-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_active_connection_MARSHAL_H__ -#define __dbus_glib_marshal_nm_active_connection_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_active_connection_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_active_connection_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_active_connection_object_info = { 1, - dbus_glib_nm_active_connection_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Connection.Active\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Connection.Active\0Connection\0connection\0read\0org.freedesktop.NetworkManager.Connection.Active\0SpecificObject\0specific_object\0read\0org.freedesktop.NetworkManager.Connection.Active\0Id\0id\0read\0org.freedesktop.NetworkManager.Connection.Active\0Uuid\0uuid\0read\0org.freedesktop.NetworkManager.Connection.Active\0Type\0type\0read\0org.freedesktop.NetworkManager.Connection.Active\0Devices\0devices\0read\0org.freedesktop.NetworkManager.Connection.Active\0State\0state\0read\0org.freedesktop.NetworkManager.Connection.Active\0Default\0default\0read\0org.freedesktop.NetworkManager.Connection.Active\0Ip4Config\0ip4_config\0read\0org.freedesktop.NetworkManager.Connection.Active\0Dhcp4Config\0dhcp4_config\0read\0org.freedesktop.NetworkManager.Connection.Active\0Default6\0default6\0read\0org.freedesktop.NetworkManager.Connection.Active\0Ip6Config\0ip6_config\0read\0org.freedesktop.NetworkManager.Connection.Active\0Dhcp6Config\0dhcp6_config\0read\0org.freedesktop.NetworkManager.Connection.Active\0Vpn\0vpn\0read\0org.freedesktop.NetworkManager.Connection.Active\0Master\0master\0read\0\0" -}; - diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 3a8e6cf5..ad6b08b3 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -20,33 +20,29 @@ #include "config.h" -#include - -#include "nm-types.h" +#include "nm-default.h" #include "nm-active-connection.h" #include "nm-dbus-interface.h" -#include "nm-logging.h" -#include "nm-dbus-glib-types.h" -#include "nm-dbus-manager.h" #include "nm-device.h" #include "nm-settings-connection.h" +#include "nm-simple-connection.h" #include "nm-auth-utils.h" #include "nm-auth-subject.h" #include "NetworkManagerUtils.h" -#include "gsystem-local-alloc.h" -#include "nm-active-connection-glue.h" -#include "nm-glib-compat.h" +#include "nm-core-internal.h" + +#include "nmdbus-active-connection.h" /* Base class for anything implementing the Connection.Active D-Bus interface */ -G_DEFINE_ABSTRACT_TYPE (NMActiveConnection, nm_active_connection, G_TYPE_OBJECT) +G_DEFINE_ABSTRACT_TYPE (NMActiveConnection, nm_active_connection, NM_TYPE_EXPORTED_OBJECT) #define NM_ACTIVE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ NM_TYPE_ACTIVE_CONNECTION, \ NMActiveConnectionPrivate)) typedef struct { - NMConnection *connection; - char *path; + NMSettingsConnection *settings_connection; + NMConnection *applied_connection; char *specific_object; NMDevice *device; @@ -89,7 +85,7 @@ enum { PROP_VPN, PROP_MASTER, - PROP_INT_CONNECTION, + PROP_INT_SETTINGS_CONNECTION, PROP_INT_DEVICE, PROP_INT_SUBJECT, PROP_INT_MASTER, @@ -114,42 +110,27 @@ static void _device_cleanup (NMActiveConnection *self); #define _NMLOG_PREFIX_NAME "active-connection" #define _NMLOG(level, ...) \ G_STMT_START { \ - const NMLogLevel __level = (level); \ + char _sbuf[64]; \ \ - if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \ - char __prefix[128]; \ - const char *__p_prefix = _NMLOG_PREFIX_NAME; \ - const void *const __self = (self); \ - \ - if (__self) { \ - g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \ - __p_prefix = __prefix; \ - } \ - _nm_log (__level, _NMLOG_DOMAIN, 0, \ - "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ - __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ - } \ + nm_log ((level), _NMLOG_DOMAIN, \ + "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + self ? nm_sprintf_buf (_sbuf, "[%p]", self) : "" \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } G_STMT_END /****************************************************************/ -static const char * -state_to_string (NMActiveConnectionState state) -{ - switch (state) { - case NM_ACTIVE_CONNECTION_STATE_UNKNOWN: - return "unknown"; - case NM_ACTIVE_CONNECTION_STATE_ACTIVATING: - return "activating"; - case NM_ACTIVE_CONNECTION_STATE_ACTIVATED: - return "activated"; - case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING: - return "deactivating"; - case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED: - return "deactivated"; - } - return "(none)"; -} +NM_UTILS_STRING_LOOKUP_TABLE_DEFINE_STATIC (_state_to_string, NMActiveConnectionState, NULL, + [NM_ACTIVE_CONNECTION_STATE_UNKNOWN] = "unknown", + [NM_ACTIVE_CONNECTION_STATE_ACTIVATING] = "activating", + [NM_ACTIVE_CONNECTION_STATE_ACTIVATED] = "activated", + [NM_ACTIVE_CONNECTION_STATE_DEACTIVATING] = "deactivating", + [NM_ACTIVE_CONNECTION_STATE_DEACTIVATED] = "deactivated", +); +#define state_to_string(state) NM_UTILS_STRING_LOOKUP_TABLE (_state_to_string, state) + +/****************************************************************/ NMActiveConnectionState nm_active_connection_get_state (NMActiveConnection *self) @@ -171,6 +152,10 @@ nm_active_connection_set_state (NMActiveConnection *self, if (priv->state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) g_return_if_fail (new_state != NM_ACTIVE_CONNECTION_STATE_DEACTIVATED); + _LOGD ("set state %s (was %s)", + state_to_string (new_state), + state_to_string (priv->state)); + old_state = priv->state; priv->state = new_state; priv->state_set = TRUE; @@ -180,7 +165,7 @@ nm_active_connection_set_state (NMActiveConnection *self, if ( new_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED || old_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { - nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (priv->connection), + nm_settings_connection_update_timestamp (priv->settings_connection, (guint64) time (NULL), TRUE); } @@ -213,59 +198,120 @@ nm_active_connection_set_state (NMActiveConnection *self, } const char * -nm_active_connection_get_id (NMActiveConnection *self) +nm_active_connection_get_settings_connection_id (NMActiveConnection *self) { + NMSettingsConnection *con; + g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); - return nm_connection_get_id (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection); + con = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection; + return con + ? nm_connection_get_id (NM_CONNECTION (con)) + : NULL; } -const char * -nm_active_connection_get_uuid (NMActiveConnection *self) +NMSettingsConnection * +_nm_active_connection_get_settings_connection (NMActiveConnection *self) { g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); - return nm_connection_get_uuid (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection); + return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->settings_connection; } -NMConnection * -nm_active_connection_get_connection (NMActiveConnection *self) +NMSettingsConnection * +nm_active_connection_get_settings_connection (NMActiveConnection *self) { - return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection; + NMSettingsConnection *con; + + con = _nm_active_connection_get_settings_connection (self); + + /* Only call this function on an active-connection that is already + * fully set-up (i.e. that has a settings-connection). Other uses + * indicate a bug. */ + g_return_val_if_fail (con, NULL); + return con; } -const char * -nm_active_connection_get_connection_type (NMActiveConnection *self) +NMConnection * +nm_active_connection_get_applied_connection (NMActiveConnection *self) { - NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + NMConnection *con; + + g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL); - if (priv->connection == NULL) - return NULL; + con = NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->applied_connection; - return nm_connection_get_connection_type (priv->connection); + /* Only call this function on an active-connection that is already + * fully set-up (i.e. that has a settings-connection). Other uses + * indicate a bug. */ + g_return_val_if_fail (con, NULL); + return con; } void -nm_active_connection_set_connection (NMActiveConnection *self, - NMConnection *connection) +nm_active_connection_set_settings_connection (NMActiveConnection *self, + NMSettingsConnection *connection) { - NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + NMActiveConnectionPrivate *priv; + + g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self)); - /* Can't change connection after the ActiveConnection is exported over D-Bus */ - g_return_if_fail (priv->path == NULL); - g_return_if_fail (priv->connection == NULL || !NM_IS_SETTINGS_CONNECTION (priv->connection)); + priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - if (priv->connection) - g_object_unref (priv->connection); - priv->connection = g_object_ref (connection); + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection)); + g_return_if_fail (!priv->settings_connection); + g_return_if_fail (!priv->applied_connection); + + /* Can't change connection after the ActiveConnection is exported over D-Bus. + * + * Later, we want to change the settings-connection of an activated connection. + * When doing that, this changes the assumption that the settings-connection + * never changes (once it's set). That has effects for NMVpnConnection and + * NMActivationRequest. + * For example, we'd have to cancel all pending seret requests. */ + g_return_if_fail (!nm_exported_object_is_exported (NM_EXPORTED_OBJECT (self))); + + priv->settings_connection = g_object_ref (connection); + priv->applied_connection = nm_simple_connection_new_clone (NM_CONNECTION (priv->settings_connection)); + nm_connection_clear_secrets (priv->applied_connection); } -const char * -nm_active_connection_get_path (NMActiveConnection *self) +gboolean +nm_active_connection_has_unmodified_applied_connection (NMActiveConnection *self, NMSettingCompareFlags compare_flags) +{ + NMActiveConnectionPrivate *priv; + + g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE); + + priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + + g_return_val_if_fail (priv->settings_connection, FALSE); + + return nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection, + priv->applied_connection, + compare_flags); +} + +/*******************************************************************/ + +void +nm_active_connection_clear_secrets (NMActiveConnection *self) { - return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->path; + NMActiveConnectionPrivate *priv; + + g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self)); + + priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + + if (nm_settings_connection_has_unmodified_applied_connection (priv->settings_connection, + priv->applied_connection, + NM_SETTING_COMPARE_FLAG_NONE)) + nm_connection_clear_secrets ((NMConnection *) priv->settings_connection); + nm_connection_clear_secrets (priv->applied_connection); } +/*******************************************************************/ + const char * nm_active_connection_get_specific_object (NMActiveConnection *self) { @@ -341,18 +387,6 @@ nm_active_connection_get_default6 (NMActiveConnection *self) return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->is_default6; } -void -nm_active_connection_export (NMActiveConnection *self) -{ - NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - static guint32 counter = 0; - - g_assert (priv->device || priv->vpn); - - priv->path = g_strdup_printf (NM_DBUS_PATH "/ActiveConnection/%d", counter++); - nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->path, self); -} - NMAuthSubject * nm_active_connection_get_subject (NMActiveConnection *self) { @@ -450,6 +484,14 @@ nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device) if (device == priv->device) return TRUE; + _LOGD ("set device %s%s%s [%p]", + NM_PRINT_FMT_QUOTED (device && nm_device_get_iface (device), + "\"", + nm_device_get_iface (device), + "\"", + device ? "(unknown)" : "(null)"), + device); + old_device = priv->device ? g_object_ref (priv->device) : NULL; _device_cleanup (self); @@ -459,7 +501,7 @@ nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device) priv->device = g_object_ref (device); - g_signal_connect (device, "state-changed", + g_signal_connect (device, NM_DEVICE_STATE_CHANGED, G_CALLBACK (device_state_changed), self); g_signal_connect (device, "notify::master", G_CALLBACK (device_master_changed), self); @@ -470,8 +512,13 @@ nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device) priv->pending_activation_id = g_strdup_printf ("activation::%p", (void *)self); nm_device_add_pending_action (device, priv->pending_activation_id, TRUE); } - } else + } else { + /* The ActiveConnection's device can only be cleared after the + * connection is activated. + */ + g_warn_if_fail (priv->state > NM_ACTIVE_CONNECTION_STATE_UNKNOWN); priv->device = NULL; + } g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_DEVICE); g_signal_emit (self, signals[DEVICE_CHANGED], 0, priv->device, old_device); @@ -508,34 +555,34 @@ static void check_master_ready (NMActiveConnection *self) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); - NMActiveConnectionState master_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN; - - if (priv->state != NM_ACTIVE_CONNECTION_STATE_ACTIVATING) { - _LOGD ("not signalling master-ready (not activating)"); - return; - } - if (!priv->master) { - _LOGD ("not signalling master-ready (no master)"); - return; - } - if (priv->master_ready) { - _LOGD ("not signalling master-ready (already signaled)"); - return; - } + gboolean signalling = FALSE; /* ActiveConnetions don't enter the ACTIVATING state until they have a * NMDevice in PREPARE or higher states, so the master active connection's * device will be ready to accept slaves when the master is in ACTIVATING * or higher states. */ - master_state = nm_active_connection_get_state (priv->master); - _LOGD ("master ActiveConnection [%p] state now '%s' (%d)", - priv->master, state_to_string (master_state), master_state); - - if ( master_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING - || master_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { - _LOGD ("signalling master-ready"); + if ( !priv->master_ready + && priv->master + && priv->state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING + && NM_IN_SET (nm_active_connection_get_state (priv->master), + NM_ACTIVE_CONNECTION_STATE_ACTIVATING, + NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) { + signalling = TRUE; + } + _LOGD ("check-master-ready: %s (state %s, %s)", + signalling + ? "signal" + : (priv->master_ready ? "already signalled" : "not signalling"), + state_to_string (priv->state), + priv->master + ? nm_sprintf_bufa (128, "master %p is in state %s", + priv->master, + state_to_string (nm_active_connection_get_state (priv->master))) + : "no master"); + + if (signalling) { priv->master_ready = TRUE; g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_MASTER_READY); @@ -553,17 +600,14 @@ master_state_cb (NMActiveConnection *master, gpointer user_data) { NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data); - NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); NMActiveConnectionState master_state = nm_active_connection_get_state (master); + NMDevice *master_device = nm_active_connection_get_device (master); check_master_ready (self); - _LOGD ("master ActiveConnection [%p] state now '%s' (%d)", - master, state_to_string (master_state), master_state); - - if ( master_state >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING - && !priv->master_ready) { - /* Master failed without ever creating its device */ + if ( master_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATING + && (!master_device || !nm_device_is_real (master_device))) { + /* Master failed without ever creating or realizing its device */ if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed) NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed (self); } @@ -590,14 +634,16 @@ nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *m /* Master is write-once, and must be set before exporting the object */ g_return_if_fail (priv->master == NULL); - g_return_if_fail (priv->path == NULL); + g_return_if_fail (!nm_exported_object_is_exported (NM_EXPORTED_OBJECT (self))); if (priv->device) { /* Note, the master ActiveConnection may not yet have a device */ g_return_if_fail (priv->device != nm_active_connection_get_device (master)); } - _LOGD ("master ActiveConnection is [%p] %s", - master, nm_active_connection_get_id (master)); + _LOGD ("set master %p, %s, state %s", + master, + nm_active_connection_get_settings_connection_id (master), + state_to_string (nm_active_connection_get_state (master))); priv->master = g_object_ref (master); g_signal_connect (priv->master, @@ -633,7 +679,7 @@ nm_active_connection_get_assumed (NMActiveConnection *self) static void auth_done (NMAuthChain *chain, GError *error, - DBusGMethodInvocation *unused, + GDBusMethodInvocation *unused, gpointer user_data) { NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data); @@ -692,6 +738,9 @@ done: /** * nm_active_connection_authorize: * @self: the #NMActiveConnection + * @initial_connection: (allow-none): for add-and-activate, there + * is no @settings_connection available when creating the active connection. + * Instead pass an alternative connection. * @result_func: function to be called on success or error * @user_data1: pointer passed to @result_func * @user_data2: additional pointer passed to @result_func @@ -702,16 +751,29 @@ done: */ void nm_active_connection_authorize (NMActiveConnection *self, + NMConnection *initial_connection, NMActiveConnectionAuthResultFunc result_func, gpointer user_data1, gpointer user_data2) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); const char *wifi_permission = NULL; + NMConnection *con; g_return_if_fail (result_func != NULL); g_return_if_fail (priv->chain == NULL); + if (initial_connection) { + g_return_if_fail (NM_IS_CONNECTION (initial_connection)); + g_return_if_fail (!priv->settings_connection); + g_return_if_fail (!priv->applied_connection); + con = initial_connection; + } else { + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (priv->settings_connection)); + g_return_if_fail (NM_IS_CONNECTION (priv->applied_connection)); + con = priv->applied_connection; + } + priv->chain = nm_auth_chain_new_subject (priv->subject, NULL, auth_done, self); g_assert (priv->chain); @@ -719,7 +781,7 @@ nm_active_connection_authorize (NMActiveConnection *self, nm_auth_chain_add_call (priv->chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); /* Shared wifi connections require special permissions too */ - wifi_permission = nm_utils_get_shared_wifi_permission (priv->connection); + wifi_permission = nm_utils_get_shared_wifi_permission (con); if (wifi_permission) { priv->wifi_shared_permission = wifi_permission; nm_auth_chain_add_call (priv->chain, wifi_permission, TRUE); @@ -736,28 +798,42 @@ nm_active_connection_authorize (NMActiveConnection *self, static void nm_active_connection_init (NMActiveConnection *self) { + _LOGT ("creating"); } static void constructed (GObject *object) { + NMActiveConnection *self = (NMActiveConnection *) object; + NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + G_OBJECT_CLASS (nm_active_connection_parent_class)->constructed (object); - g_assert (NM_ACTIVE_CONNECTION_GET_PRIVATE (object)->subject); + + _LOGD ("constructed (%s)", G_OBJECT_TYPE_NAME (self)); + + g_return_if_fail (priv->subject); } static void set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) + const GValue *value, GParamSpec *pspec) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object); const char *tmp; + NMSettingsConnection *con; switch (prop_id) { - case PROP_INT_CONNECTION: - g_warn_if_fail (priv->connection == NULL); - priv->connection = g_value_dup_object (value); + case PROP_INT_SETTINGS_CONNECTION: + /* construct-only */ + con = g_value_get_object (value); + if (con) { + priv->settings_connection = g_object_ref (con); + priv->applied_connection = nm_simple_connection_new_clone (NM_CONNECTION (con)); + nm_connection_clear_secrets (priv->applied_connection); + } break; case PROP_INT_DEVICE: + /* construct-only */ nm_active_connection_set_device (NM_ACTIVE_CONNECTION (object), g_value_get_object (value)); break; case PROP_INT_SUBJECT: @@ -767,10 +843,10 @@ set_property (GObject *object, guint prop_id, nm_active_connection_set_master (NM_ACTIVE_CONNECTION (object), g_value_get_object (value)); break; case PROP_SPECIFIC_OBJECT: - tmp = g_value_get_boxed (value); + tmp = g_value_get_string (value); /* NM uses "/" to mean NULL */ if (g_strcmp0 (tmp, "/") != 0) - priv->specific_object = g_value_dup_boxed (value); + priv->specific_object = g_strdup (tmp); break; case PROP_DEFAULT: priv->is_default = !!g_value_get_boolean (value); @@ -791,7 +867,7 @@ set_property (GObject *object, guint prop_id, static void get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) + GValue *value, GParamSpec *pspec) { NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object); GPtrArray *devices; @@ -799,25 +875,26 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_CONNECTION: - g_value_set_boxed (value, nm_connection_get_path (priv->connection)); + g_value_set_string (value, nm_connection_get_path (NM_CONNECTION (priv->settings_connection))); break; case PROP_ID: - g_value_set_string (value, nm_connection_get_id (priv->connection)); + g_value_set_string (value, nm_connection_get_id (NM_CONNECTION (priv->settings_connection))); break; case PROP_UUID: - g_value_set_string (value, nm_connection_get_uuid (priv->connection)); + g_value_set_string (value, nm_connection_get_uuid (NM_CONNECTION (priv->settings_connection))); break; case PROP_TYPE: - g_value_set_string (value, nm_connection_get_connection_type (priv->connection)); + g_value_set_string (value, nm_connection_get_connection_type (NM_CONNECTION (priv->settings_connection))); break; case PROP_SPECIFIC_OBJECT: - g_value_set_boxed (value, priv->specific_object ? priv->specific_object : "/"); + g_value_set_string (value, priv->specific_object ? priv->specific_object : "/"); break; case PROP_DEVICES: - devices = g_ptr_array_sized_new (1); + devices = g_ptr_array_sized_new (2); if (priv->device && priv->state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) - g_ptr_array_add (devices, g_strdup (nm_device_get_path (priv->device))); - g_value_take_boxed (value, devices); + g_ptr_array_add (devices, g_strdup (nm_exported_object_get_path (NM_EXPORTED_OBJECT (priv->device)))); + g_ptr_array_add (devices, NULL); + g_value_take_boxed (value, (char **) g_ptr_array_free (devices, FALSE)); break; case PROP_STATE: if (priv->state_set) @@ -834,19 +911,19 @@ get_property (GObject *object, guint prop_id, break; case PROP_IP4_CONFIG: /* The IP and DHCP config properties may be overridden by a subclass */ - g_value_set_boxed (value, "/"); + g_value_set_string (value, "/"); break; case PROP_DHCP4_CONFIG: - g_value_set_boxed (value, "/"); + g_value_set_string (value, "/"); break; case PROP_DEFAULT6: g_value_set_boolean (value, priv->is_default6); break; case PROP_IP6_CONFIG: - g_value_set_boxed (value, "/"); + g_value_set_string (value, "/"); break; case PROP_DHCP6_CONFIG: - g_value_set_boxed (value, "/"); + g_value_set_string (value, "/"); break; case PROP_VPN: g_value_set_boolean (value, priv->vpn); @@ -854,7 +931,7 @@ get_property (GObject *object, guint prop_id, case PROP_MASTER: if (priv->master) master_device = nm_active_connection_get_device (priv->master); - g_value_set_boxed (value, master_device ? nm_device_get_path (master_device) : "/"); + nm_utils_g_value_set_object_path (value, master_device); break; case PROP_INT_SUBJECT: g_value_set_object (value, priv->subject); @@ -893,17 +970,18 @@ dispose (GObject *object) NMActiveConnection *self = NM_ACTIVE_CONNECTION (object); NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self); + _LOGD ("disposing"); + if (priv->chain) { nm_auth_chain_unref (priv->chain); priv->chain = NULL; } - g_free (priv->path); - priv->path = NULL; g_free (priv->specific_object); priv->specific_object = NULL; - g_clear_object (&priv->connection); + g_clear_object (&priv->settings_connection); + g_clear_object (&priv->applied_connection); _device_cleanup (self); @@ -922,9 +1000,12 @@ static void nm_active_connection_class_init (NMActiveConnectionClass *ac_class) { GObjectClass *object_class = G_OBJECT_CLASS (ac_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (ac_class); g_type_class_add_private (ac_class, sizeof (NMActiveConnectionPrivate)); + exported_object_class->export_path = NM_DBUS_PATH "/ActiveConnection/%u"; + /* virtual methods */ object_class->get_property = get_property; object_class->set_property = set_property; @@ -934,10 +1015,10 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) /* D-Bus exported properties */ g_object_class_install_property (object_class, PROP_CONNECTION, - g_param_spec_boxed (NM_ACTIVE_CONNECTION_CONNECTION, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_ACTIVE_CONNECTION_CONNECTION, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_ID, @@ -962,15 +1043,15 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) g_object_class_install_property (object_class, PROP_SPECIFIC_OBJECT, - g_param_spec_boxed (NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, "", "", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_DEVICES, g_param_spec_boxed (NM_ACTIVE_CONNECTION_DEVICES, "", "", - DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, + G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -992,17 +1073,17 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) g_object_class_install_property (object_class, PROP_IP4_CONFIG, - g_param_spec_boxed (NM_ACTIVE_CONNECTION_IP4_CONFIG, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_ACTIVE_CONNECTION_IP4_CONFIG, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_DHCP4_CONFIG, - g_param_spec_boxed (NM_ACTIVE_CONNECTION_DHCP4_CONFIG, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_ACTIVE_CONNECTION_DHCP4_CONFIG, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_DEFAULT6, @@ -1013,17 +1094,17 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) g_object_class_install_property (object_class, PROP_IP6_CONFIG, - g_param_spec_boxed (NM_ACTIVE_CONNECTION_IP6_CONFIG, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_ACTIVE_CONNECTION_IP6_CONFIG, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_DHCP6_CONFIG, - g_param_spec_boxed (NM_ACTIVE_CONNECTION_DHCP6_CONFIG, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_ACTIVE_CONNECTION_DHCP6_CONFIG, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_VPN, @@ -1034,24 +1115,24 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) g_object_class_install_property (object_class, PROP_MASTER, - g_param_spec_boxed (NM_ACTIVE_CONNECTION_MASTER, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_ACTIVE_CONNECTION_MASTER, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); /* Internal properties */ g_object_class_install_property - (object_class, PROP_INT_CONNECTION, - g_param_spec_object (NM_ACTIVE_CONNECTION_INT_CONNECTION, "", "", - NM_TYPE_CONNECTION, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + (object_class, PROP_INT_SETTINGS_CONNECTION, + g_param_spec_object (NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION, "", "", + NM_TYPE_SETTINGS_CONNECTION, + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_INT_DEVICE, g_param_spec_object (NM_ACTIVE_CONNECTION_INT_DEVICE, "", "", NM_TYPE_DEVICE, - G_PARAM_READWRITE | + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property @@ -1090,8 +1171,8 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class) NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (ac_class), - &dbus_glib_nm_active_connection_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (ac_class), + NMDBUS_TYPE_ACTIVE_CONNECTION_SKELETON, + NULL); } diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h index 4db5e6ff..f57f2081 100644 --- a/src/nm-active-connection.h +++ b/src/nm-active-connection.h @@ -21,8 +21,7 @@ #ifndef __NETWORKMANAGER_ACTIVE_CONNECTION_H__ #define __NETWORKMANAGER_ACTIVE_CONNECTION_H__ -#include -#include "nm-types.h" +#include "nm-exported-object.h" #include "nm-connection.h" #define NM_TYPE_ACTIVE_CONNECTION (nm_active_connection_get_type ()) @@ -50,7 +49,7 @@ #define NM_ACTIVE_CONNECTION_MASTER "master" /* Internal non-exported properties */ -#define NM_ACTIVE_CONNECTION_INT_CONNECTION "int-connection" +#define NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION "int-settings-connection" #define NM_ACTIVE_CONNECTION_INT_DEVICE "int-device" #define NM_ACTIVE_CONNECTION_INT_SUBJECT "int-subject" #define NM_ACTIVE_CONNECTION_INT_MASTER "int-master" @@ -61,11 +60,11 @@ #define NM_ACTIVE_CONNECTION_DEVICE_METERED_CHANGED "device-metered-changed" struct _NMActiveConnection { - GObject parent; + NMExportedObject parent; }; typedef struct { - GObjectClass parent; + NMExportedObjectClass parent; /* re-emits device state changes as a convenience for subclasses for * device states >= DISCONNECTED. @@ -93,24 +92,23 @@ typedef void (*NMActiveConnectionAuthResultFunc) (NMActiveConnection *self, gpointer user_data2); void nm_active_connection_authorize (NMActiveConnection *self, + NMConnection *initial_connection, NMActiveConnectionAuthResultFunc result_func, gpointer user_data1, gpointer user_data2); -void nm_active_connection_export (NMActiveConnection *self); +NMSettingsConnection *nm_active_connection_get_settings_connection (NMActiveConnection *self); +NMConnection *nm_active_connection_get_applied_connection (NMActiveConnection *self); -NMConnection *nm_active_connection_get_connection (NMActiveConnection *self); +NMSettingsConnection *_nm_active_connection_get_settings_connection (NMActiveConnection *self); -void nm_active_connection_set_connection (NMActiveConnection *self, - NMConnection *connection); +void nm_active_connection_set_settings_connection (NMActiveConnection *self, + NMSettingsConnection *connection); -const char * nm_active_connection_get_id (NMActiveConnection *self); +gboolean nm_active_connection_has_unmodified_applied_connection (NMActiveConnection *self, + NMSettingCompareFlags compare_flags); -const char * nm_active_connection_get_uuid (NMActiveConnection *self); - -const char * nm_active_connection_get_connection_type (NMActiveConnection *self); - -const char * nm_active_connection_get_path (NMActiveConnection *self); +const char * nm_active_connection_get_settings_connection_id (NMActiveConnection *self); const char * nm_active_connection_get_specific_object (NMActiveConnection *self); @@ -152,4 +150,6 @@ void nm_active_connection_set_assumed (NMActiveConnection *self, gboolean nm_active_connection_get_assumed (NMActiveConnection *self); +void nm_active_connection_clear_secrets (NMActiveConnection *self); + #endif /* __NETWORKMANAGER_ACTIVE_CONNECTION_H__ */ diff --git a/src/nm-agent-manager-glue.h b/src/nm-agent-manager-glue.h deleted file mode 100644 index e6431f53..00000000 --- a/src/nm-agent-manager-glue.h +++ /dev/null @@ -1,170 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_agent_manager_MARSHAL_H__ -#define __dbus_glib_marshal_nm_agent_manager_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -/* NONE:POINTER */ -#define dbus_glib_marshal_nm_agent_manager_VOID__POINTER g_cclosure_marshal_VOID__POINTER -#define dbus_glib_marshal_nm_agent_manager_NONE__POINTER dbus_glib_marshal_nm_agent_manager_VOID__POINTER - -/* NONE:STRING,UINT,POINTER */ -extern void dbus_glib_marshal_nm_agent_manager_VOID__STRING_UINT_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_agent_manager_VOID__STRING_UINT_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__STRING_UINT_POINTER) (gpointer data1, - gpointer arg_1, - guint arg_2, - gpointer arg_3, - gpointer data2); - GMarshalFunc_VOID__STRING_UINT_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - - g_return_if_fail (n_param_values == 4); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_VOID__STRING_UINT_POINTER) (marshal_data ? marshal_data : cc->callback); - - callback (data1, - g_marshal_value_peek_string (param_values + 1), - g_marshal_value_peek_uint (param_values + 2), - g_marshal_value_peek_pointer (param_values + 3), - data2); -} -#define dbus_glib_marshal_nm_agent_manager_NONE__STRING_UINT_POINTER dbus_glib_marshal_nm_agent_manager_VOID__STRING_UINT_POINTER - -/* NONE:STRING,POINTER */ -extern void dbus_glib_marshal_nm_agent_manager_VOID__STRING_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_agent_manager_VOID__STRING_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__STRING_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer data2); - GMarshalFunc_VOID__STRING_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_VOID__STRING_POINTER) (marshal_data ? marshal_data : cc->callback); - - callback (data1, - g_marshal_value_peek_string (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - data2); -} -#define dbus_glib_marshal_nm_agent_manager_NONE__STRING_POINTER dbus_glib_marshal_nm_agent_manager_VOID__STRING_POINTER - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_agent_manager_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_agent_manager_methods[] = { - { (GCallback) impl_agent_manager_register, dbus_glib_marshal_nm_agent_manager_NONE__STRING_POINTER, 0 }, - { (GCallback) impl_agent_manager_register_with_capabilities, dbus_glib_marshal_nm_agent_manager_NONE__STRING_UINT_POINTER, 71 }, - { (GCallback) impl_agent_manager_unregister, dbus_glib_marshal_nm_agent_manager_NONE__POINTER, 175 }, -}; - -const DBusGObjectInfo dbus_glib_nm_agent_manager_object_info = { 1, - dbus_glib_nm_agent_manager_methods, - 3, -"org.freedesktop.NetworkManager.AgentManager\0Register\0A\0identifier\0I\0s\0\0org.freedesktop.NetworkManager.AgentManager\0RegisterWithCapabilities\0A\0identifier\0I\0s\0capabilities\0I\0u\0\0org.freedesktop.NetworkManager.AgentManager\0Unregister\0A\0\0\0", -"\0", -"\0" -}; - diff --git a/src/nm-audit-manager.c b/src/nm-audit-manager.c new file mode 100644 index 00000000..007e4321 --- /dev/null +++ b/src/nm-audit-manager.c @@ -0,0 +1,389 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager audit support + * + * 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 2015 Red Hat, Inc. + */ + +#include "config.h" + +#include +#include +#if HAVE_LIBAUDIT +#include +#endif + +#include "gsystem-local-alloc.h" +#include "nm-audit-manager.h" +#include "nm-glib.h" +#include "nm-auth-subject.h" +#include "nm-config.h" +#include "nm-logging.h" +#include "nm-macros-internal.h" +#include "nm-settings-connection.h" + +#define AUDIT_LOG_LEVEL LOGL_INFO + +typedef enum { + BACKEND_LOG = (1 << 0), + BACKEND_AUDITD = (1 << 1), + _BACKEND_LAST, + BACKEND_ALL = ((_BACKEND_LAST - 1) << 1) - 1, +} AuditBackend; + +typedef struct { + const char *name; + GValue value; + gboolean need_encoding; + AuditBackend backends; +} AuditField; + +#if HAVE_LIBAUDIT +typedef struct { + NMConfig *config; + int auditd_fd; +} NMAuditManagerPrivate; + +#define NM_AUDIT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AUDIT_MANAGER, NMAuditManagerPrivate)) +#endif + +G_DEFINE_TYPE (NMAuditManager, nm_audit_manager, G_TYPE_OBJECT) + +NM_DEFINE_SINGLETON_GETTER (NMAuditManager, nm_audit_manager_get, NM_TYPE_AUDIT_MANAGER); + +static void +_audit_field_init_string (AuditField *field, const char *name, const char *str, + gboolean need_encoding, AuditBackend backends) +{ + field->name = name; + field->need_encoding = need_encoding; + field->backends = backends; + g_value_init (&field->value, G_TYPE_STRING); + g_value_set_static_string (&field->value, str); +} + +static void +_audit_field_init_uint (AuditField *field, const char *name, uint val, + AuditBackend backends) +{ + field->name = name; + field->backends = backends; + g_value_init (&field->value, G_TYPE_UINT); + g_value_set_uint (&field->value, val); +} + +static char * +build_message (GPtrArray *fields, AuditBackend backend) +{ + GString *string; + AuditField *field; + gboolean first = TRUE; + guint i; + + string = g_string_new (NULL); + + for (i = 0; i < fields->len; i++) { + field = fields->pdata[i]; + + if (!NM_FLAGS_HAS (field->backends, backend)) + continue; + + if (first) + first = FALSE; + else + g_string_append_c (string, ' '); + + if (G_VALUE_HOLDS_STRING (&field->value)) { + const char *str = g_value_get_string (&field->value); + +#if HAVE_LIBAUDIT + if (backend == BACKEND_AUDITD) { + if (field->need_encoding) { + char *value; + + value = audit_encode_nv_string (field->name, str, 0); + g_string_append (string, value); + g_free (value); + } else + g_string_append_printf (string, "%s=%s", field->name, str); + continue; + } +#endif /* HAVE_LIBAUDIT */ + g_string_append_printf (string, "%s=\"%s\"", field->name, str); + } else if (G_VALUE_HOLDS_UINT (&field->value)) { + g_string_append_printf (string, "%s=%u", field->name, + g_value_get_uint (&field->value)); + } else + g_assert_not_reached (); + } + return g_string_free (string, FALSE); +} + + +static void +nm_audit_log (NMAuditManager *self, GPtrArray *fields, const char *file, + guint line, const char *func, gboolean success) +{ +#if HAVE_LIBAUDIT + NMAuditManagerPrivate *priv; +#endif + char *msg; + + g_return_if_fail (NM_IS_AUDIT_MANAGER (self)); + +#if HAVE_LIBAUDIT + priv = NM_AUDIT_MANAGER_GET_PRIVATE (self); + + if (priv->auditd_fd >= 0) { + msg = build_message (fields, BACKEND_AUDITD); + audit_log_user_message (priv->auditd_fd, AUDIT_USYS_CONFIG, msg, + NULL, NULL, NULL, success); + g_free (msg); + } +#endif + + if (nm_logging_enabled (AUDIT_LOG_LEVEL, LOGD_AUDIT)) { + msg = build_message (fields, BACKEND_LOG); + _nm_log_impl (file, line, func, AUDIT_LOG_LEVEL, LOGD_AUDIT, 0, "%s", msg); + g_free (msg); + } +} + +static void +_audit_log_helper (NMAuditManager *self, GPtrArray *fields, const char *file, + guint line, const char *func, const char *op, gboolean result, + gpointer subject_context, const char *reason) +{ + AuditField op_field = { }, pid_field = { }, uid_field = { }; + AuditField result_field = { }, reason_field = { }; + gulong pid, uid; + NMAuthSubject *subject = NULL; + gs_unref_object NMAuthSubject *subject_free = NULL; + + _audit_field_init_string (&op_field, "op", op, FALSE, BACKEND_ALL); + g_ptr_array_insert (fields, 0, &op_field); + + if (subject_context) { + if (NM_IS_AUTH_SUBJECT (subject_context)) + subject = subject_context; + else if (G_IS_DBUS_METHOD_INVOCATION (subject_context)) { + GDBusMethodInvocation *context = subject_context; + + subject = subject_free = nm_auth_subject_new_unix_process_from_context (context); + } else + g_warn_if_reached (); + } + if (subject && nm_auth_subject_is_unix_process (subject)) { + pid = nm_auth_subject_get_unix_process_pid (subject); + uid = nm_auth_subject_get_unix_process_uid (subject); + if (pid != G_MAXULONG) { + _audit_field_init_uint (&pid_field, "pid", pid, BACKEND_ALL); + g_ptr_array_add (fields, &pid_field); + } + if (uid != G_MAXULONG) { + _audit_field_init_uint (&uid_field, "uid", uid, BACKEND_ALL); + g_ptr_array_add (fields, &uid_field); + } + } + + _audit_field_init_string (&result_field, "result", result ? "success" : "fail", + FALSE, BACKEND_ALL); + g_ptr_array_add (fields, &result_field); + + if (reason) { + _audit_field_init_string (&reason_field, "reason", reason, FALSE, BACKEND_LOG); + g_ptr_array_add (fields, &reason_field); + } + + nm_audit_log (self, fields, file, line, func, result); +} + +gboolean +nm_audit_manager_audit_enabled (NMAuditManager *self) +{ +#if HAVE_LIBAUDIT + NMAuditManagerPrivate *priv = NM_AUDIT_MANAGER_GET_PRIVATE (self); + + if (priv->auditd_fd >= 0) + return TRUE; +#endif + + return nm_logging_enabled (AUDIT_LOG_LEVEL, LOGD_AUDIT); +} + +void +_nm_audit_manager_log_connection_op (NMAuditManager *self, const char *file, guint line, + const char *func, const char *op, NMSettingsConnection *connection, + gboolean result, gpointer subject_context, const char *reason) +{ + gs_unref_ptrarray GPtrArray *fields = NULL; + AuditField uuid_field = { }, name_field = { }; + + g_return_if_fail (op); + + fields = g_ptr_array_new (); + + if (connection) { + _audit_field_init_string (&uuid_field, "uuid", nm_settings_connection_get_uuid (connection), + FALSE, BACKEND_ALL); + g_ptr_array_add (fields, &uuid_field); + + _audit_field_init_string (&name_field, "name", nm_settings_connection_get_id (connection), + TRUE, BACKEND_ALL); + g_ptr_array_add (fields, &name_field); + } + + _audit_log_helper (self, fields, file, line, func, op, result, subject_context, reason); +} + +void +_nm_audit_manager_log_control_op (NMAuditManager *self, const char *file, guint line, + const char *func, const char *op, const char *arg, + gboolean result, gpointer subject_context, + const char *reason) +{ + gs_unref_ptrarray GPtrArray *fields = NULL; + AuditField arg_field = { }; + + g_return_if_fail (op); + g_return_if_fail (arg); + + fields = g_ptr_array_new (); + + _audit_field_init_string (&arg_field, "arg", arg, TRUE, BACKEND_ALL); + g_ptr_array_add (fields, &arg_field); + + _audit_log_helper (self, fields, file, line, func, op, result, subject_context, reason); +} + +void +_nm_audit_manager_log_device_op (NMAuditManager *self, const char *file, guint line, + const char *func, const char *op, NMDevice *device, + gboolean result, gpointer subject_context, + const char *reason) +{ + gs_unref_ptrarray GPtrArray *fields = NULL; + AuditField interface_field = { }, ifindex_field = { }; + int ifindex; + + g_return_if_fail (op); + g_return_if_fail (device); + + fields = g_ptr_array_new (); + + _audit_field_init_string (&interface_field, "interface", nm_device_get_ip_iface (device), + TRUE, BACKEND_ALL); + g_ptr_array_add (fields, &interface_field); + + ifindex = nm_device_get_ip_ifindex (device); + if (ifindex > 0) { + _audit_field_init_uint (&ifindex_field, "ifindex", ifindex, BACKEND_ALL); + g_ptr_array_add (fields, &ifindex_field); + } + + _audit_log_helper (self, fields, file, line, func, op, result, subject_context, reason); +} + +#if HAVE_LIBAUDIT +static void +init_auditd (NMAuditManager *self) +{ + NMAuditManagerPrivate *priv = NM_AUDIT_MANAGER_GET_PRIVATE (self); + NMConfigData *data = nm_config_get_data (priv->config); + + if (nm_config_data_get_value_boolean (data, NM_CONFIG_KEYFILE_GROUP_LOGGING, + NM_CONFIG_KEYFILE_KEY_AUDIT, + NM_CONFIG_DEFAULT_LOGGING_AUDIT)) { + if (priv->auditd_fd < 0) { + priv->auditd_fd = audit_open (); + if (priv->auditd_fd < 0) { + nm_log_err (LOGD_CORE, "failed to open auditd socket: %s", + strerror (errno)); + } else + nm_log_dbg (LOGD_CORE, "audit socket created"); + } + } else { + if (priv->auditd_fd >= 0) { + audit_close (priv->auditd_fd); + priv->auditd_fd = -1; + nm_log_dbg (LOGD_CORE, "audit socket closed"); + } + } +} + +static void +config_changed_cb (NMConfig *config, + NMConfigData *config_data, + NMConfigChangeFlags changes, + NMConfigData *old_data, + NMAuditManager *self) +{ + if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_VALUES)) + init_auditd (self); +} +#endif + +static void +nm_audit_manager_init (NMAuditManager *self) +{ +#if HAVE_LIBAUDIT + NMAuditManagerPrivate *priv = NM_AUDIT_MANAGER_GET_PRIVATE (self); + + priv->config = g_object_ref (nm_config_get ()); + g_signal_connect (G_OBJECT (priv->config), + NM_CONFIG_SIGNAL_CONFIG_CHANGED, + G_CALLBACK (config_changed_cb), + self); + priv->auditd_fd = -1; + + init_auditd (self); +#endif +} + +static void +dispose (GObject *object) +{ +#if HAVE_LIBAUDIT + NMAuditManager *self = NM_AUDIT_MANAGER (object); + NMAuditManagerPrivate *priv = NM_AUDIT_MANAGER_GET_PRIVATE (self); + + if (priv->config) { + g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self); + g_clear_object (&priv->config); + } + + if (priv->auditd_fd >= 0) { + audit_close (priv->auditd_fd); + priv->auditd_fd = -1; + } +#endif + + G_OBJECT_CLASS (nm_audit_manager_parent_class)->dispose (object); +} + +static void +nm_audit_manager_class_init (NMAuditManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + +#if HAVE_LIBAUDIT + g_type_class_add_private (klass, sizeof (NMAuditManagerPrivate)); +#endif + + /* virtual methods */ + object_class->dispose = dispose; +} + diff --git a/src/nm-audit-manager.h b/src/nm-audit-manager.h new file mode 100644 index 00000000..ed53be69 --- /dev/null +++ b/src/nm-audit-manager.h @@ -0,0 +1,114 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager audit support + * + * 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 2015 Red Hat, Inc. + */ + +#ifndef __NM_AUDIT_MANAGER_H__ +#define __NM_AUDIT_MANAGER_H__ + +#include +#include + +#include "nm-connection.h" +#include "nm-device.h" +#include "nm-types.h" + +G_BEGIN_DECLS + +#define NM_TYPE_AUDIT_MANAGER (nm_audit_manager_get_type ()) +#define NM_AUDIT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_AUDIT_MANAGER, NMAuditManager)) +#define NM_AUDIT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_AUDIT_MANAGER, NMAuditManagerClass)) +#define NM_IS_AUDIT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_AUDIT_MANAGER)) +#define NM_IS_AUDIT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_AUDIT_MANAGER)) +#define NM_AUDIT_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AUDIT_MANAGER, NMAuditManagerClass)) + +struct _NMAuditManager { + GObject parent; +}; + +typedef struct { + GObjectClass parent; +} NMAuditManagerClass; + +#define NM_AUDIT_OP_CONN_ADD "connection-add" +#define NM_AUDIT_OP_CONN_DELETE "connection-delete" +#define NM_AUDIT_OP_CONN_UPDATE "connection-update" +#define NM_AUDIT_OP_CONN_ACTIVATE "connection-activate" +#define NM_AUDIT_OP_CONN_ADD_ACTIVATE "connection-add-activate" +#define NM_AUDIT_OP_CONN_DEACTIVATE "connection-deactivate" +#define NM_AUDIT_OP_CONN_CLEAR_SECRETS "connection-clear-secrets" + +#define NM_AUDIT_OP_SLEEP_CONTROL "sleep-control" +#define NM_AUDIT_OP_NET_CONTROL "networking-control" +#define NM_AUDIT_OP_RADIO_CONTROL "radio-control" + +#define NM_AUDIT_OP_DEVICE_AUTOCONNECT "device-autoconnect" +#define NM_AUDIT_OP_DEVICE_DISCONNECT "device-disconnect" +#define NM_AUDIT_OP_DEVICE_DELETE "device-delete" +#define NM_AUDIT_OP_DEVICE_MANAGED "device-managed" +#define NM_AUDIT_OP_DEVICE_REAPPLY "device-reapply" + +GType nm_audit_manager_get_type (void); +NMAuditManager *nm_audit_manager_get (void); +gboolean nm_audit_manager_audit_enabled (NMAuditManager *self); + +#define nm_audit_log_connection_op(op, connection, result, subject_context, reason) \ + G_STMT_START { \ + NMAuditManager *_audit = nm_audit_manager_get (); \ + \ + if (nm_audit_manager_audit_enabled (_audit)) { \ + _nm_audit_manager_log_connection_op (_audit, __FILE__, __LINE__, G_STRFUNC, \ + (op), (connection), (result), (subject_context), \ + (reason)); \ + } \ + } G_STMT_END + +#define nm_audit_log_control_op(op, arg, result, subject_context, reason) \ + G_STMT_START { \ + NMAuditManager *_audit = nm_audit_manager_get (); \ + \ + if (nm_audit_manager_audit_enabled (_audit)) { \ + _nm_audit_manager_log_control_op (_audit, __FILE__, __LINE__, G_STRFUNC, \ + (op), (arg), (result), (subject_context), (reason)); \ + } \ + } G_STMT_END + +#define nm_audit_log_device_op(op, device, result, subject_context, reason) \ + G_STMT_START { \ + NMAuditManager *_audit = nm_audit_manager_get (); \ + \ + if (nm_audit_manager_audit_enabled (_audit)) { \ + _nm_audit_manager_log_device_op (_audit, __FILE__, __LINE__, G_STRFUNC, \ + (op), (device), (result), (subject_context), (reason)); \ + } \ + } G_STMT_END + +void _nm_audit_manager_log_connection_op (NMAuditManager *self, const char *file, guint line, + const char *func, const char *op, NMSettingsConnection *connection, + gboolean result, gpointer subject_context, const char *reason); + +void _nm_audit_manager_log_control_op (NMAuditManager *self, const char *file, guint line, + const char *func, const char *op, const char *arg, + gboolean result, gpointer subject_context, const char *reason); + +void _nm_audit_manager_log_device_op (NMAuditManager *self, const char *file, guint line, + const char *func, const char *op, NMDevice *device, + gboolean result, gpointer subject_context, const char *reason); +G_END_DECLS + +#endif /* __NM_AUDIT_MANAGER_H__ */ diff --git a/src/nm-auth-manager.c b/src/nm-auth-manager.c index 09a5791f..bc519eb1 100644 --- a/src/nm-auth-manager.c +++ b/src/nm-auth-manager.c @@ -22,8 +22,10 @@ #include "nm-auth-manager.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-errors.h" +#include "nm-core-internal.h" +#include "NetworkManagerUtils.h" #define POLKIT_SERVICE "org.freedesktop.PolicyKit1" #define POLKIT_OBJECT_PATH "/org/freedesktop/PolicyKit1/Authority" @@ -70,7 +72,7 @@ typedef struct { #endif } NMAuthManagerPrivate; -static NMAuthManager *singleton_instance = NULL; +NM_DEFINE_SINGLETON_REGISTER (NMAuthManager); G_DEFINE_TYPE (NMAuthManager, nm_auth_manager, G_TYPE_OBJECT) @@ -145,6 +147,7 @@ cancel_check_authorization_cb (GDBusProxy *proxy, value = g_dbus_proxy_call_finish (proxy, res, &error); if (value == NULL) { + g_dbus_error_strip_remote_error (error); _LOGD ("Error cancelling authorization check: %s", error->message); g_error_free (error); } else @@ -169,12 +172,11 @@ check_authorization_cb (GDBusProxy *proxy, GVariant *value; GError *error = NULL; - value = g_dbus_proxy_call_finish (proxy, res, &error); + value = _nm_dbus_proxy_call_finish (proxy, res, G_VARIANT_TYPE ("((bba{ss}))"), &error); if (value == NULL) { if (data->cancellation_id != NULL && - (!g_dbus_error_is_remote_error (error) && - error->domain == G_IO_ERROR && - error->code == G_IO_ERROR_CANCELLED)) { + ( g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) + && !g_dbus_error_is_remote_error (error))) { _LOGD ("call[%u]: CheckAuthorization cancelled", data->call_id); g_dbus_proxy_call (priv->proxy, "CancelCheckAuthorization", @@ -186,6 +188,7 @@ check_authorization_cb (GDBusProxy *proxy, g_object_ref (self)); } else _LOGD ("call[%u]: CheckAuthorization failed: %s", data->call_id, error->message); + g_dbus_error_strip_remote_error (error); g_simple_async_result_set_error (data->simple, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, @@ -193,18 +196,15 @@ check_authorization_cb (GDBusProxy *proxy, error->message); g_error_free (error); } else { - GVariant *result_value; CheckAuthorizationResult *result; result = g_new0 (CheckAuthorizationResult, 1); - result_value = g_variant_get_child_value (value, 0); - g_variant_get (result_value, - "(bb@a{ss})", + g_variant_get (value, + "((bb@a{ss}))", &result->is_authorized, &result->is_challenge, NULL); - g_variant_unref (result_value); g_variant_unref (value); _LOGD ("call[%u]: CheckAuthorization succeeded: (is_authorized=%d, is_challenge=%d)", data->call_id, result->is_authorized, result->is_challenge); @@ -387,21 +387,16 @@ _dbus_on_name_owner_notify_cb (GObject *object, } static void -_dbus_on_g_signal_cb (GDBusProxy *proxy, - const gchar *sender_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) +_dbus_on_changed_signal_cb (GDBusProxy *proxy, + gpointer user_data) { NMAuthManager *self = user_data; NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); g_return_if_fail (priv->proxy == proxy); - _LOGD ("dbus signal: \"%s\"", signal_name ? signal_name : "(null)"); - - if (g_strcmp0 (signal_name, "Changed") == 0) - _emit_changed_signal (self); + _LOGD ("dbus signal: \"Changed\""); + _emit_changed_signal (self); } static void @@ -456,10 +451,9 @@ _dbus_new_proxy_cb (GObject *source_object, "notify::g-name-owner", G_CALLBACK (_dbus_on_name_owner_notify_cb), self); - g_signal_connect (priv->proxy, - "g-signal", - G_CALLBACK (_dbus_on_g_signal_cb), - self); + _nm_dbus_signal_connect (priv->proxy, "Changed", NULL, + G_CALLBACK (_dbus_on_changed_signal_cb), + self); _log_name_owner (self, NULL); @@ -496,7 +490,12 @@ nm_auth_manager_setup (gboolean polkit_enabled) NULL); _LOGD ("set instance"); - return (singleton_instance = self); + singleton_instance = self; + nm_singleton_instance_register (); + + nm_log_dbg (LOGD_CORE, "setup %s singleton (%p)", "NMAuthManager", singleton_instance); + + return self; } /*****************************************************************************/ @@ -594,8 +593,7 @@ dispose (GObject *object) } if (priv->proxy) { - g_signal_handlers_disconnect_by_func (priv->proxy, _dbus_on_name_owner_notify_cb, self); - g_signal_handlers_disconnect_by_func (priv->proxy, _dbus_on_g_signal_cb, self); + g_signal_handlers_disconnect_by_data (priv->proxy, self); g_clear_object (&priv->proxy); } #endif @@ -603,19 +601,6 @@ dispose (GObject *object) G_OBJECT_CLASS (nm_auth_manager_parent_class)->dispose (object); } -static void -finalize (GObject *object) -{ - NMAuthManager* self = NM_AUTH_MANAGER (object); - - G_OBJECT_CLASS (nm_auth_manager_parent_class)->finalize (object); - - if (self == singleton_instance) { - singleton_instance = NULL; - _LOGD ("unset instance"); - } -} - static void nm_auth_manager_class_init (NMAuthManagerClass *klass) { @@ -627,7 +612,6 @@ nm_auth_manager_class_init (NMAuthManagerClass *klass) object_class->set_property = set_property; object_class->constructed = constructed; object_class->dispose = dispose; - object_class->finalize = finalize; g_object_class_install_property (object_class, PROP_POLKIT_ENABLED, diff --git a/src/nm-auth-manager.h b/src/nm-auth-manager.h index cc3b5d3c..2875cccb 100644 --- a/src/nm-auth-manager.h +++ b/src/nm-auth-manager.h @@ -21,8 +21,8 @@ #ifndef NM_AUTH_MANAGER_H #define NM_AUTH_MANAGER_H -#include +#include "nm-default.h" #include "nm-auth-subject.h" G_BEGIN_DECLS diff --git a/src/nm-auth-subject.c b/src/nm-auth-subject.c index c67424e7..c4b6e579 100644 --- a/src/nm-auth-subject.c +++ b/src/nm-auth-subject.c @@ -32,13 +32,11 @@ #include #include -#include -#include "nm-dbus-manager.h" +#include "nm-default.h" +#include "nm-bus-manager.h" #include "nm-enum-types.h" -#include "nm-glib-compat.h" #include "NetworkManagerUtils.h" -#include "gsystem-local-alloc.h" G_DEFINE_TYPE (NMAuthSubject, nm_auth_subject, G_TYPE_OBJECT) @@ -169,9 +167,9 @@ nm_auth_subject_get_unix_process_dbus_sender (NMAuthSubject *subject) /**************************************************************/ static NMAuthSubject * -_new_unix_process (DBusGMethodInvocation *context, - DBusConnection *connection, - DBusMessage *message) +_new_unix_process (GDBusMethodInvocation *context, + GDBusConnection *connection, + GDBusMessage *message) { NMAuthSubject *self; gboolean success = FALSE; @@ -181,18 +179,18 @@ _new_unix_process (DBusGMethodInvocation *context, g_return_val_if_fail (context || (connection && message), NULL); if (context) { - success = nm_dbus_manager_get_caller_info (nm_dbus_manager_get (), - context, - &dbus_sender, - &uid, - &pid); + success = nm_bus_manager_get_caller_info (nm_bus_manager_get (), + context, + &dbus_sender, + &uid, + &pid); } else if (message) { - success = nm_dbus_manager_get_caller_info_from_message (nm_dbus_manager_get (), - connection, - message, - &dbus_sender, - &uid, - &pid); + success = nm_bus_manager_get_caller_info_from_message (nm_bus_manager_get (), + connection, + message, + &dbus_sender, + &uid, + &pid); } else g_assert_not_reached (); @@ -223,14 +221,14 @@ _new_unix_process (DBusGMethodInvocation *context, } NMAuthSubject * -nm_auth_subject_new_unix_process_from_context (DBusGMethodInvocation *context) +nm_auth_subject_new_unix_process_from_context (GDBusMethodInvocation *context) { return _new_unix_process (context, NULL, NULL); } NMAuthSubject * -nm_auth_subject_new_unix_process_from_message (DBusConnection *connection, - DBusMessage *message) +nm_auth_subject_new_unix_process_from_message (GDBusConnection *connection, + GDBusMessage *message) { return _new_unix_process (NULL, connection, message); } diff --git a/src/nm-auth-subject.h b/src/nm-auth-subject.h index cc004fa9..1682ba7f 100644 --- a/src/nm-auth-subject.h +++ b/src/nm-auth-subject.h @@ -21,13 +21,9 @@ #ifndef __NETWORKMANAGER_AUTH_SUBJECT_H__ #define __NETWORKMANAGER_AUTH_SUBJECT_H__ -#include -#include -#include -#include -#include +#include "config.h" -#include "nm-types.h" +#include "nm-default.h" #define NM_TYPE_AUTH_SUBJECT (nm_auth_subject_get_type ()) #define NM_AUTH_SUBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_AUTH_SUBJECT, NMAuthSubject)) @@ -59,9 +55,9 @@ GType nm_auth_subject_get_type (void); NMAuthSubject *nm_auth_subject_new_internal (void); -NMAuthSubject *nm_auth_subject_new_unix_process_from_context (DBusGMethodInvocation *context); +NMAuthSubject *nm_auth_subject_new_unix_process_from_context (GDBusMethodInvocation *context); -NMAuthSubject *nm_auth_subject_new_unix_process_from_message (DBusConnection *connection, DBusMessage *message); +NMAuthSubject *nm_auth_subject_new_unix_process_from_message (GDBusConnection *connection, GDBusMessage *message); NMAuthSubjectType nm_auth_subject_get_subject_type (NMAuthSubject *subject); diff --git a/src/nm-auth-utils.c b/src/nm-auth-utils.c index b2ca800c..8c1c4dac 100644 --- a/src/nm-auth-utils.c +++ b/src/nm-auth-utils.c @@ -21,13 +21,10 @@ #include "config.h" #include -#include -#include "gsystem-local-alloc.h" +#include "nm-default.h" #include "nm-setting-connection.h" #include "nm-auth-utils.h" -#include "nm-logging.h" -#include "nm-dbus-manager.h" #include "nm-auth-subject.h" #include "nm-auth-manager.h" #include "nm-session-monitor.h" @@ -37,11 +34,12 @@ struct NMAuthChain { GSList *calls; GHashTable *data; - DBusGMethodInvocation *context; + GDBusMethodInvocation *context; NMAuthSubject *subject; GError *error; guint idle_id; + gboolean done; NMAuthChainResultFunc done_func; gpointer user_data; @@ -59,15 +57,26 @@ typedef struct { GDestroyNotify destroy; } ChainData; +static ChainData * +chain_data_new (gpointer data, GDestroyNotify destroy) +{ + ChainData *tmp; + + tmp = g_slice_new (ChainData); + tmp->data = data; + tmp->destroy = destroy; + return tmp; +} + static void -free_data (gpointer data) +chain_data_free (gpointer data) { ChainData *tmp = data; if (tmp->destroy) tmp->destroy (tmp->data); memset (tmp, 0, sizeof (ChainData)); - g_free (tmp); + g_slice_free (ChainData, tmp); } static gboolean @@ -76,8 +85,9 @@ auth_chain_finish (gpointer user_data) NMAuthChain *self = user_data; self->idle_id = 0; + self->done = TRUE; - /* Ensure we say alive across the callback */ + /* Ensure we stay alive across the callback */ self->refcount++; self->done_func (self, self->error, self->context, self->user_data); nm_auth_chain_unref (self); @@ -86,7 +96,7 @@ auth_chain_finish (gpointer user_data) /* Creates the NMAuthSubject automatically */ NMAuthChain * -nm_auth_chain_new_context (DBusGMethodInvocation *context, +nm_auth_chain_new_context (GDBusMethodInvocation *context, NMAuthChainResultFunc done_func, gpointer user_data) { @@ -110,7 +120,7 @@ nm_auth_chain_new_context (DBusGMethodInvocation *context, /* Requires an NMAuthSubject */ NMAuthChain * nm_auth_chain_new_subject (NMAuthSubject *subject, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, NMAuthChainResultFunc done_func, gpointer user_data) { @@ -119,27 +129,33 @@ nm_auth_chain_new_subject (NMAuthSubject *subject, g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); g_return_val_if_fail (nm_auth_subject_is_unix_process (subject) || nm_auth_subject_is_internal (subject), NULL); - self = g_malloc0 (sizeof (NMAuthChain)); + self = g_slice_new0 (NMAuthChain); self->refcount = 1; - self->data = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_data); + self->data = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, chain_data_free); self->done_func = done_func; self->user_data = user_data; - self->context = context; + self->context = context ? g_object_ref (context) : NULL; self->subject = g_object_ref (subject); return self; } -gpointer -nm_auth_chain_get_data (NMAuthChain *self, const char *tag) +static gpointer +_get_data (NMAuthChain *self, const char *tag) { ChainData *tmp; + tmp = g_hash_table_lookup (self->data, tag); + return tmp ? tmp->data : NULL; +} + +gpointer +nm_auth_chain_get_data (NMAuthChain *self, const char *tag) +{ g_return_val_if_fail (self != NULL, NULL); g_return_val_if_fail (tag != NULL, NULL); - tmp = g_hash_table_lookup (self->data, tag); - return tmp ? tmp->data : NULL; + return _get_data (self, tag); } /** @@ -168,7 +184,7 @@ nm_auth_chain_steal_data (NMAuthChain *self, const char *tag) value = tmp->data; /* Make sure the destroy handler isn't called when freeing */ tmp->destroy = NULL; - free_data (tmp); + chain_data_free (tmp); g_free (orig_key); } return value; @@ -180,35 +196,30 @@ nm_auth_chain_set_data (NMAuthChain *self, gpointer data, GDestroyNotify data_destroy) { - ChainData *tmp; - g_return_if_fail (self != NULL); g_return_if_fail (tag != NULL); if (data == NULL) g_hash_table_remove (self->data, tag); else { - tmp = g_malloc0 (sizeof (ChainData)); - tmp->data = data; - tmp->destroy = data_destroy; - - g_hash_table_insert (self->data, g_strdup (tag), tmp); + g_hash_table_insert (self->data, + g_strdup (tag), + chain_data_new (data, data_destroy)); } } gulong nm_auth_chain_get_data_ulong (NMAuthChain *self, const char *tag) { - gulong *ptr; + gulong *data; g_return_val_if_fail (self != NULL, 0); g_return_val_if_fail (tag != NULL, 0); - ptr = nm_auth_chain_get_data (self, tag); - return *ptr; + data = _get_data (self, tag); + return data ? *data : 0ul; } - void nm_auth_chain_set_data_ulong (NMAuthChain *self, const char *tag, @@ -224,33 +235,24 @@ nm_auth_chain_set_data_ulong (NMAuthChain *self, nm_auth_chain_set_data (self, tag, ptr, g_free); } -NMAuthCallResult -nm_auth_chain_get_result (NMAuthChain *self, const char *permission) +NMAuthSubject * +nm_auth_chain_get_subject (NMAuthChain *self) { - g_return_val_if_fail (self != NULL, NM_AUTH_CALL_RESULT_UNKNOWN); - g_return_val_if_fail (permission != NULL, NM_AUTH_CALL_RESULT_UNKNOWN); + g_return_val_if_fail (self != NULL, NULL); - return GPOINTER_TO_UINT (nm_auth_chain_get_data (self, permission)); + return self->subject; } -static void -nm_auth_chain_check_done (NMAuthChain *self) +NMAuthCallResult +nm_auth_chain_get_result (NMAuthChain *self, const char *permission) { - g_return_if_fail (self != NULL); - - if (g_slist_length (self->calls) == 0) { - g_assert (self->idle_id == 0); - self->idle_id = g_idle_add (auth_chain_finish, self); - } -} + gpointer data; -static void -nm_auth_chain_remove_call (NMAuthChain *self, AuthCall *call) -{ - g_return_if_fail (self != NULL); - g_return_if_fail (call != NULL); + g_return_val_if_fail (self != NULL, NM_AUTH_CALL_RESULT_UNKNOWN); + g_return_val_if_fail (permission != NULL, NM_AUTH_CALL_RESULT_UNKNOWN); - self->calls = g_slist_remove (self->calls, call); + data = _get_data (self, permission); + return data ? GPOINTER_TO_UINT (data) : NM_AUTH_CALL_RESULT_UNKNOWN; } static AuthCall * @@ -258,10 +260,9 @@ auth_call_new (NMAuthChain *chain, const char *permission) { AuthCall *call; - call = g_malloc0 (sizeof (AuthCall)); + call = g_slice_new0 (AuthCall); call->chain = chain; call->permission = g_strdup (permission); - chain->calls = g_slist_append (chain->calls, call); return call; } @@ -270,15 +271,27 @@ auth_call_free (AuthCall *call) { g_free (call->permission); g_clear_object (&call->cancellable); - g_free (call); + g_slice_free (AuthCall, call); } -/* This can get used from scheduled idles, hence the boolean return */ static gboolean auth_call_complete (AuthCall *call) { - nm_auth_chain_remove_call (call->chain, call); - nm_auth_chain_check_done (call->chain); + NMAuthChain *self; + + g_return_val_if_fail (call, G_SOURCE_REMOVE); + + self = call->chain; + + g_return_val_if_fail (self, G_SOURCE_REMOVE); + g_return_val_if_fail (g_slist_find (self->calls, call), G_SOURCE_REMOVE); + + self->calls = g_slist_remove (self->calls, call); + + if (!self->calls) { + g_assert (!self->idle_id && !self->done); + self->idle_id = g_idle_add (auth_chain_finish, self); + } auth_call_free (call); return FALSE; } @@ -362,8 +375,10 @@ nm_auth_chain_add_call (NMAuthChain *self, g_return_if_fail (permission && *permission); g_return_if_fail (self->subject); g_return_if_fail (nm_auth_subject_is_unix_process (self->subject) || nm_auth_subject_is_internal (self->subject)); + g_return_if_fail (!self->idle_id && !self->done); call = auth_call_new (self, permission); + self->calls = g_slist_append (self->calls, call); if ( nm_auth_subject_is_internal (self->subject) || nm_auth_subject_get_unix_process_uid (self->subject) == 0 @@ -393,10 +408,21 @@ nm_auth_chain_add_call (NMAuthChain *self, } } +/** + * nm_auth_chain_unref: + * @self: the auth-chain + * + * Unrefs the auth-chain. By unrefing the auth-chain, you also cancel + * the receipt of the done-callback. IOW, the callback will not be invoked. + * + * The only exception is, if you call nm_auth_chain_unref() from inside + * the callback. In this case, @self stays alive until the callback returns. + */ void nm_auth_chain_unref (NMAuthChain *self) { g_return_if_fail (self != NULL); + g_return_if_fail (self->refcount > 0); self->refcount--; if (self->refcount > 0) @@ -407,30 +433,30 @@ nm_auth_chain_unref (NMAuthChain *self) g_object_unref (self->subject); + if (self->context) + g_object_unref (self->context); + g_slist_free_full (self->calls, auth_call_cancel); g_clear_error (&self->error); g_hash_table_destroy (self->data); memset (self, 0, sizeof (NMAuthChain)); - g_free (self); + g_slice_free (NMAuthChain, self); } /************ utils **************/ gboolean nm_auth_is_subject_in_acl (NMConnection *connection, - NMSessionMonitor *smon, NMAuthSubject *subject, char **out_error_desc) { NMSettingConnection *s_con; const char *user = NULL; - GError *local = NULL; gulong uid; g_return_val_if_fail (connection != NULL, FALSE); - g_return_val_if_fail (smon != NULL, FALSE); g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), FALSE); g_return_val_if_fail (nm_auth_subject_is_internal (subject) || nm_auth_subject_is_unix_process (subject), FALSE); @@ -443,18 +469,7 @@ nm_auth_is_subject_in_acl (NMConnection *connection, if (0 == uid) return TRUE; - /* Reject the request if the request comes from no session at all */ - if (!nm_session_monitor_uid_has_session (smon, uid, &user, &local)) { - if (out_error_desc) { - *out_error_desc = g_strdup_printf ("No session found for uid %lu (%s)", - uid, - local && local->message ? local->message : "unknown"); - } - g_clear_error (&local); - return FALSE; - } - - if (!user) { + if (!nm_session_monitor_uid_to_user (uid, &user)) { if (out_error_desc) *out_error_desc = g_strdup_printf ("Could not determine username for uid %lu", uid); return FALSE; diff --git a/src/nm-auth-utils.h b/src/nm-auth-utils.h index 2ab026d0..6eb0fda0 100644 --- a/src/nm-auth-utils.h +++ b/src/nm-auth-utils.h @@ -21,11 +21,8 @@ #ifndef __NETWORKMANAGER_MANAGER_AUTH_H__ #define __NETWORKMANAGER_MANAGER_AUTH_H__ -#include -#include - #include -#include "nm-types.h" +#include "nm-default.h" #define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK "org.freedesktop.NetworkManager.enable-disable-network" #define NM_AUTH_PERMISSION_SLEEP_WAKE "org.freedesktop.NetworkManager.sleep-wake" @@ -38,6 +35,7 @@ #define NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM "org.freedesktop.NetworkManager.settings.modify.system" #define NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN "org.freedesktop.NetworkManager.settings.modify.own" #define NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME "org.freedesktop.NetworkManager.settings.modify.hostname" +#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS "org.freedesktop.NetworkManager.settings.modify.global-dns" typedef struct NMAuthChain NMAuthChain; @@ -51,15 +49,15 @@ typedef enum { typedef void (*NMAuthChainResultFunc) (NMAuthChain *chain, GError *error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, gpointer user_data); -NMAuthChain *nm_auth_chain_new_context (DBusGMethodInvocation *context, +NMAuthChain *nm_auth_chain_new_context (GDBusMethodInvocation *context, NMAuthChainResultFunc done_func, gpointer user_data); NMAuthChain *nm_auth_chain_new_subject (NMAuthSubject *subject, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, NMAuthChainResultFunc done_func, gpointer user_data); @@ -89,9 +87,10 @@ void nm_auth_chain_unref (NMAuthChain *chain); /* Caller must free returned error description */ gboolean nm_auth_is_subject_in_acl (NMConnection *connection, - NMSessionMonitor *smon, NMAuthSubject *subect, char **out_error_desc); +NMAuthSubject *nm_auth_chain_get_subject (NMAuthChain *self); + #endif /* __NETWORKMANAGER_MANAGER_AUTH_H__ */ diff --git a/src/nm-bus-manager.c b/src/nm-bus-manager.c new file mode 100644 index 00000000..a82b3883 --- /dev/null +++ b/src/nm-bus-manager.c @@ -0,0 +1,949 @@ +/* -*- 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) 2006 - 2013 Red Hat, Inc. + * Copyright (C) 2006 - 2008 Novell, Inc. + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "nm-default.h" +#include "nm-dbus-interface.h" +#include "nm-bus-manager.h" +#include "nm-core-internal.h" +#include "nm-dbus-compat.h" +#include "nm-exported-object.h" +#include "NetworkManagerUtils.h" + +enum { + DBUS_CONNECTION_CHANGED = 0, + PRIVATE_CONNECTION_NEW, + PRIVATE_CONNECTION_DISCONNECTED, + NUMBER_OF_SIGNALS +}; + +static guint signals[NUMBER_OF_SIGNALS]; + +G_DEFINE_TYPE(NMBusManager, nm_bus_manager, G_TYPE_OBJECT) + +#define NM_BUS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ + NM_TYPE_BUS_MANAGER, \ + NMBusManagerPrivate)) + +typedef struct _PrivateServer PrivateServer; + +typedef struct { + GDBusConnection *connection; + GDBusObjectManagerServer *obj_manager; + gboolean started; + + GSList *private_servers; + + GDBusProxy *proxy; + + gulong bus_closed_id; + guint reconnect_id; +} NMBusManagerPrivate; + +static gboolean nm_bus_manager_init_bus (NMBusManager *self); +static void nm_bus_manager_cleanup (NMBusManager *self); +static void start_reconnection_timeout (NMBusManager *self); + +/* The base path for our GDBusObjectManagerServers. They do not contain + * "NetworkManager" because GDBusObjectManagerServer requires that all + * exported objects be *below* the base path, and eg the Manager object + * is the base path already. + */ +#define OBJECT_MANAGER_SERVER_BASE_PATH "/org/freedesktop" + +NM_DEFINE_SINGLETON_REGISTER (NMBusManager); + +NMBusManager * +nm_bus_manager_get (void) +{ + if (G_UNLIKELY (!singleton_instance)) { + nm_bus_manager_setup (g_object_new (NM_TYPE_BUS_MANAGER, NULL)); + if (!nm_bus_manager_init_bus (singleton_instance)) + start_reconnection_timeout (singleton_instance); + } + return singleton_instance; +} + +void +nm_bus_manager_setup (NMBusManager *instance) +{ + static char already_setup = FALSE; + + g_assert (NM_IS_BUS_MANAGER (instance)); + g_assert (!already_setup); + g_assert (!singleton_instance); + + already_setup = TRUE; + singleton_instance = instance; + nm_singleton_instance_register (); + nm_log_dbg (LOGD_CORE, "setup %s singleton (%p)", "NMBusManager", singleton_instance); +} + +/**************************************************************/ + +struct _PrivateServer { + const char *tag; + GQuark detail; + char *address; + GDBusServer *server; + + /* With peer bus connections, we'll get a new connection for each + * client. For each connection we create an ObjectManager for + * that connection to handle exporting our objects. This table + * maps GDBusObjectManager :: 'fake sender'. + * + * Note that even for connections that don't export any objects + * we'll still create GDBusObjectManager since that's where we store + * the pointer to the GDBusConnection. + */ + GHashTable *obj_managers; + + NMBusManager *manager; +}; + +typedef struct { + GDBusConnection *connection; + PrivateServer *server; + gboolean remote_peer_vanished; +} CloseConnectionInfo; + +static gboolean +close_connection_in_idle (gpointer user_data) +{ + CloseConnectionInfo *info = user_data; + PrivateServer *server = info->server; + GHashTableIter iter; + GDBusObjectManagerServer *manager; + + /* Emit this for the manager */ + g_signal_emit (server->manager, + signals[PRIVATE_CONNECTION_DISCONNECTED], + server->detail, + info->connection); + + /* FIXME: there's a bug (754730) in GLib for which the connection + * is marked as closed when the remote peer vanishes but its + * resources are not cleaned up. Work around it by explicitly + * closing the connection in that case. */ + if (info->remote_peer_vanished) + g_dbus_connection_close (info->connection, NULL, NULL, NULL); + + g_hash_table_iter_init (&iter, server->obj_managers); + while (g_hash_table_iter_next (&iter, (gpointer) &manager, NULL)) { + if (g_dbus_object_manager_server_get_connection (manager) == info->connection) { + g_hash_table_iter_remove (&iter); + break; + } + } + + g_object_unref (server->manager); + g_slice_free (CloseConnectionInfo, info); + + return G_SOURCE_REMOVE; +} + +static void +private_server_closed_connection (GDBusConnection *conn, + gboolean remote_peer_vanished, + GError *error, + gpointer user_data) +{ + PrivateServer *s = user_data; + CloseConnectionInfo *info; + + /* Clean up after the connection */ + nm_log_dbg (LOGD_CORE, "(%s) closed connection %p on private socket.", + s->tag, conn); + + info = g_slice_new0 (CloseConnectionInfo); + info->connection = conn; + info->server = s; + info->remote_peer_vanished = remote_peer_vanished; + + g_object_ref (s->manager); + + /* Delay the close of connection to ensure that D-Bus signals + * are handled */ + g_idle_add (close_connection_in_idle, info); +} + +static gboolean +private_server_new_connection (GDBusServer *server, + GDBusConnection *conn, + gpointer user_data) +{ + PrivateServer *s = user_data; + static guint32 counter = 0; + GDBusObjectManagerServer *manager; + char *sender; + + g_signal_connect (conn, "closed", G_CALLBACK (private_server_closed_connection), s); + + /* Fake a sender since private connections don't have one */ + sender = g_strdup_printf ("x:y:%d", counter++); + + manager = g_dbus_object_manager_server_new (OBJECT_MANAGER_SERVER_BASE_PATH); + g_dbus_object_manager_server_set_connection (manager, conn); + g_hash_table_insert (s->obj_managers, manager, sender); + + nm_log_dbg (LOGD_CORE, "(%s) accepted connection %p on private socket.", + s->tag, conn); + + /* Emit this for the manager */ + g_signal_emit (s->manager, + signals[PRIVATE_CONNECTION_NEW], + s->detail, + conn, + manager); + return TRUE; +} + +static void +private_server_manager_destroy (GDBusObjectManagerServer *manager) +{ + GDBusConnection *connection = g_dbus_object_manager_server_get_connection (manager); + + if (!g_dbus_connection_is_closed (connection)) + g_dbus_connection_close (connection, NULL, NULL, NULL); + g_dbus_object_manager_server_set_connection (manager, NULL); + g_object_unref (manager); +} + +static gboolean +private_server_authorize (GDBusAuthObserver *observer, + GIOStream *stream, + GCredentials *credentials, + gpointer user_data) +{ + return g_credentials_get_unix_user (credentials, NULL) == 0; +} + +static PrivateServer * +private_server_new (const char *path, + const char *tag, + NMBusManager *manager) +{ + PrivateServer *s; + GDBusAuthObserver *auth_observer; + GDBusServer *server; + GError *error = NULL; + char *address, *guid; + + unlink (path); + address = g_strdup_printf ("unix:path=%s", path); + + nm_log_dbg (LOGD_CORE, "(%s) creating private socket %s.", tag, address); + + guid = g_dbus_generate_guid (); + auth_observer = g_dbus_auth_observer_new (); + g_signal_connect (auth_observer, "authorize-authenticated-peer", + G_CALLBACK (private_server_authorize), NULL); + server = g_dbus_server_new_sync (address, + G_DBUS_SERVER_FLAGS_NONE, + guid, + auth_observer, + NULL, &error); + g_free (guid); + g_object_unref (auth_observer); + + if (!server) { + nm_log_warn (LOGD_CORE, "(%s) failed to set up private socket %s: %s", + tag, address, error->message); + g_error_free (error); + g_free (address); + return NULL; + } + + s = g_malloc0 (sizeof (*s)); + s->address = address; + s->server = server; + g_signal_connect (server, "new-connection", + G_CALLBACK (private_server_new_connection), s); + + s->obj_managers = g_hash_table_new_full (g_direct_hash, g_direct_equal, + (GDestroyNotify) private_server_manager_destroy, + g_free); + s->manager = manager; + s->detail = g_quark_from_string (tag); + s->tag = g_quark_to_string (s->detail); + + g_dbus_server_start (server); + + return s; +} + +static void +private_server_free (gpointer ptr) +{ + PrivateServer *s = ptr; + + unlink (s->address); + g_free (s->address); + g_hash_table_destroy (s->obj_managers); + + g_dbus_server_stop (s->server); + g_object_unref (s->server); + + memset (s, 0, sizeof (*s)); + g_free (s); +} + +void +nm_bus_manager_private_server_register (NMBusManager *self, + const char *path, + const char *tag) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + PrivateServer *s; + GSList *iter; + + g_return_if_fail (self != NULL); + g_return_if_fail (path != NULL); + g_return_if_fail (tag != NULL); + + /* Only one instance per tag; but don't warn */ + for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) { + s = iter->data; + if (g_strcmp0 (tag, s->tag) == 0) + return; + } + + s = private_server_new (path, tag, self); + if (s) + priv->private_servers = g_slist_append (priv->private_servers, s); +} + +static const char * +private_server_get_connection_owner (PrivateServer *s, GDBusConnection *connection) +{ + GHashTableIter iter; + GDBusObjectManagerServer *manager; + const char *owner; + + g_return_val_if_fail (s != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + + g_hash_table_iter_init (&iter, s->obj_managers); + while (g_hash_table_iter_next (&iter, (gpointer) &manager, (gpointer) &owner)) { + if (g_dbus_object_manager_server_get_connection (manager) == connection) + return owner; + } + return NULL; +} + +static GDBusConnection * +private_server_get_connection_by_owner (PrivateServer *s, const char *owner) +{ + GHashTableIter iter; + GDBusObjectManagerServer *manager; + const char *priv_sender; + + g_hash_table_iter_init (&iter, s->obj_managers); + while (g_hash_table_iter_next (&iter, (gpointer) &manager, (gpointer) &priv_sender)) { + if (g_strcmp0 (owner, priv_sender) == 0) + return g_dbus_object_manager_server_get_connection (manager); + } + return NULL; +} + +/**************************************************************/ + +static gboolean +_bus_get_unix_pid (NMBusManager *self, + const char *sender, + gulong *out_pid, + GError **error) +{ + guint32 unix_pid = G_MAXUINT32; + GVariant *ret; + + ret = _nm_dbus_proxy_call_sync (NM_BUS_MANAGER_GET_PRIVATE (self)->proxy, + "GetConnectionUnixProcessID", + g_variant_new ("(s)", sender), + G_VARIANT_TYPE ("(u)"), + G_DBUS_CALL_FLAGS_NONE, 2000, + NULL, error); + if (!ret) + return FALSE; + + g_variant_get (ret, "(u)", &unix_pid); + + *out_pid = (gulong) unix_pid; + return TRUE; +} + +static gboolean +_bus_get_unix_user (NMBusManager *self, + const char *sender, + gulong *out_user, + GError **error) +{ + guint32 unix_uid = G_MAXUINT32; + GVariant *ret; + + ret = _nm_dbus_proxy_call_sync (NM_BUS_MANAGER_GET_PRIVATE (self)->proxy, + "GetConnectionUnixUser", + g_variant_new ("(s)", sender), + G_VARIANT_TYPE ("(u)"), + G_DBUS_CALL_FLAGS_NONE, 2000, + NULL, error); + if (!ret) + return FALSE; + + g_variant_get (ret, "(u)", &unix_uid); + + *out_user = (gulong) unix_uid; + return TRUE; +} + +/** + * _get_caller_info(): + * + * Given a GDBus method invocation, or a GDBusConnection + GDBusMessage, + * return the sender and the UID of the sender. + */ +static gboolean +_get_caller_info (NMBusManager *self, + GDBusMethodInvocation *context, + GDBusConnection *connection, + GDBusMessage *message, + char **out_sender, + gulong *out_uid, + gulong *out_pid) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + const char *sender; + GSList *iter; + + if (context) { + connection = g_dbus_method_invocation_get_connection (context); + + /* only bus connections will have a sender */ + sender = g_dbus_method_invocation_get_sender (context); + } else { + g_assert (message); + sender = g_dbus_message_get_sender (message); + } + g_assert (connection); + + if (!sender) { + /* Might be a private connection, for which we fake a sender */ + for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) { + PrivateServer *s = iter->data; + + sender = private_server_get_connection_owner (s, connection); + if (sender) { + if (out_uid) + *out_uid = 0; + if (out_sender) + *out_sender = g_strdup (sender); + if (out_pid) { + GCredentials *creds; + + creds = g_dbus_connection_get_peer_credentials (connection); + if (creds) { + pid_t pid; + + pid = g_credentials_get_unix_pid (creds, NULL); + if (pid == -1) + *out_pid = G_MAXULONG; + else + *out_pid = pid; + } else + *out_pid = G_MAXULONG; + } + return TRUE; + } + } + return FALSE; + } + + /* Bus connections always have a sender */ + g_assert (sender); + if (out_uid) { + if (!_bus_get_unix_user (self, sender, out_uid, NULL)) { + *out_uid = G_MAXULONG; + return FALSE; + } + } + + if (out_pid) { + if (!_bus_get_unix_pid (self, sender, out_pid, NULL)) { + *out_pid = G_MAXULONG; + return FALSE; + } + } + + if (out_sender) + *out_sender = g_strdup (sender); + + return TRUE; +} + +gboolean +nm_bus_manager_get_caller_info (NMBusManager *self, + GDBusMethodInvocation *context, + char **out_sender, + gulong *out_uid, + gulong *out_pid) +{ + return _get_caller_info (self, context, NULL, NULL, out_sender, out_uid, out_pid); +} + +gboolean +nm_bus_manager_get_caller_info_from_message (NMBusManager *self, + GDBusConnection *connection, + GDBusMessage *message, + char **out_sender, + gulong *out_uid, + gulong *out_pid) +{ + return _get_caller_info (self, NULL, connection, message, out_sender, out_uid, out_pid); +} + +gboolean +nm_bus_manager_get_unix_user (NMBusManager *self, + const char *sender, + gulong *out_uid) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + GSList *iter; + GError *error = NULL; + + g_return_val_if_fail (sender != NULL, FALSE); + g_return_val_if_fail (out_uid != NULL, FALSE); + + /* Check if it's a private connection sender, which we fake */ + for (iter = priv->private_servers; iter; iter = iter->next) { + if (private_server_get_connection_by_owner (iter->data, sender)) { + *out_uid = 0; + return TRUE; + } + } + + /* Otherwise, a bus connection */ + if (!_bus_get_unix_user (self, sender, out_uid, &error)) { + nm_log_warn (LOGD_CORE, "Failed to get unix user for dbus sender '%s': %s", + sender, error->message); + g_error_free (error); + return FALSE; + } + + return TRUE; +} + +/**************************************************************/ + +static void +nm_bus_manager_init (NMBusManager *self) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + + priv->obj_manager = g_dbus_object_manager_server_new (OBJECT_MANAGER_SERVER_BASE_PATH); +} + +static void +nm_bus_manager_dispose (GObject *object) +{ + NMBusManager *self = NM_BUS_MANAGER (object); + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + GList *exported, *iter; + + g_slist_free_full (priv->private_servers, private_server_free); + priv->private_servers = NULL; + + nm_bus_manager_cleanup (self); + + if (priv->obj_manager) { + /* The ObjectManager owns the last reference to many exported + * objects, and when that reference is dropped the objects unregister + * themselves via nm_bus_manager_unregister_object(). By that time + * priv->obj_manager is already NULL and that prints warnings. Unregister + * them before clearing the ObjectManager instead. + */ + exported = g_dbus_object_manager_get_objects ((GDBusObjectManager *) priv->obj_manager); + for (iter = exported; iter; iter = iter->next) { + nm_bus_manager_unregister_object (self, iter->data); + g_object_unref (iter->data); + } + g_list_free (exported); + g_clear_object (&priv->obj_manager); + } + + nm_clear_g_source (&priv->reconnect_id); + + G_OBJECT_CLASS (nm_bus_manager_parent_class)->dispose (object); +} + +static void +nm_bus_manager_class_init (NMBusManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (NMBusManagerPrivate)); + + object_class->dispose = nm_bus_manager_dispose; + + signals[DBUS_CONNECTION_CHANGED] = + g_signal_new (NM_BUS_MANAGER_DBUS_CONNECTION_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMBusManagerClass, dbus_connection_changed), + NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_POINTER); + + signals[PRIVATE_CONNECTION_NEW] = + g_signal_new (NM_BUS_MANAGER_PRIVATE_CONNECTION_NEW, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, NULL, NULL, NULL, + G_TYPE_NONE, 2, G_TYPE_DBUS_CONNECTION, G_TYPE_DBUS_OBJECT_MANAGER_SERVER); + + signals[PRIVATE_CONNECTION_DISCONNECTED] = + g_signal_new (NM_BUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + G_STRUCT_OFFSET (NMBusManagerClass, private_connection_disconnected), + NULL, NULL, NULL, + G_TYPE_NONE, 1, G_TYPE_POINTER); +} + + +/* Only cleanup a specific dbus connection, not all our private data */ +static void +nm_bus_manager_cleanup (NMBusManager *self) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + + g_clear_object (&priv->proxy); + + if (priv->connection) { + g_signal_handler_disconnect (priv->connection, priv->bus_closed_id); + priv->bus_closed_id = 0; + g_clear_object (&priv->connection); + } + + g_dbus_object_manager_server_set_connection (priv->obj_manager, NULL); + priv->started = FALSE; +} + +static gboolean +nm_bus_manager_reconnect (gpointer user_data) +{ + NMBusManager *self = NM_BUS_MANAGER (user_data); + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + + g_assert (self != NULL); + + if (nm_bus_manager_init_bus (self)) { + if (nm_bus_manager_start_service (self)) { + nm_log_info (LOGD_CORE, "reconnected to the system bus."); + g_signal_emit (self, signals[DBUS_CONNECTION_CHANGED], + 0, priv->connection); + priv->reconnect_id = 0; + return FALSE; + } + } + + /* Try again */ + nm_bus_manager_cleanup (self); + return TRUE; +} + +static void +start_reconnection_timeout (NMBusManager *self) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + + if (priv->reconnect_id) + g_source_remove (priv->reconnect_id); + + /* Schedule timeout for reconnection attempts */ + priv->reconnect_id = g_timeout_add_seconds (3, nm_bus_manager_reconnect, self); +} + +static void +closed_cb (GDBusConnection *connection, + gboolean remote_peer_vanished, + GError *error, + gpointer user_data) +{ + NMBusManager *self = NM_BUS_MANAGER (user_data); + + /* Clean up existing connection */ + nm_log_warn (LOGD_CORE, "disconnected by the system bus."); + + nm_bus_manager_cleanup (self); + + g_signal_emit (G_OBJECT (self), signals[DBUS_CONNECTION_CHANGED], 0, NULL); + + start_reconnection_timeout (self); +} + +static gboolean +nm_bus_manager_init_bus (NMBusManager *self) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + GError *error = NULL; + + if (priv->connection) { + nm_log_warn (LOGD_CORE, "DBus Manager already has a valid connection."); + return FALSE; + } + + priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); + if (!priv->connection) { + /* Log with 'info' severity; there won't be a bus daemon in minimal + * environments (eg, initrd) where we only want to use the private + * socket. + */ + nm_log_info (LOGD_CORE, "Could not connect to the system bus (%s); only the " + "private D-Bus socket will be available.", + error->message); + g_error_free (error); + return FALSE; + } + + g_dbus_connection_set_exit_on_close (priv->connection, FALSE); + priv->bus_closed_id = g_signal_connect (priv->connection, "closed", + G_CALLBACK (closed_cb), self); + + priv->proxy = g_dbus_proxy_new_sync (priv->connection, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + NULL, &error); + if (!priv->proxy) { + g_clear_object (&priv->connection); + nm_log_warn (LOGD_CORE, "Could not create org.freedesktop.DBus proxy (%s); only the " + "private D-Bus socket will be available.", + error->message); + g_error_free (error); + return FALSE; + } + + g_dbus_object_manager_server_set_connection (priv->obj_manager, priv->connection); + return TRUE; +} + +/* Register our service on the bus; shouldn't be called until + * all necessary message handlers have been registered, because + * when we register on the bus, clients may start to call. + */ +gboolean +nm_bus_manager_start_service (NMBusManager *self) +{ + NMBusManagerPrivate *priv; + GVariant *ret; + int result; + GError *err = NULL; + + g_return_val_if_fail (NM_IS_BUS_MANAGER (self), FALSE); + + priv = NM_BUS_MANAGER_GET_PRIVATE (self); + + if (priv->started) { + nm_log_err (LOGD_CORE, "Service has already started."); + return FALSE; + } + + /* Pointless to request a name when we aren't connected to the bus */ + if (!priv->proxy) + return FALSE; + + ret = _nm_dbus_proxy_call_sync (priv->proxy, + "RequestName", + g_variant_new ("(su)", + NM_DBUS_SERVICE, + DBUS_NAME_FLAG_DO_NOT_QUEUE), + G_VARIANT_TYPE ("(u)"), + G_DBUS_CALL_FLAGS_NONE, -1, + NULL, &err); + if (!ret) { + nm_log_err (LOGD_CORE, "Could not acquire the NetworkManager service.\n" + " Error: '%s'", err->message); + g_error_free (err); + return FALSE; + } + + g_variant_get (ret, "(u)", &result); + + if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + nm_log_err (LOGD_CORE, "Could not acquire the NetworkManager service as it is already taken."); + return FALSE; + } + + priv->started = TRUE; + return priv->started; +} + +GDBusConnection * +nm_bus_manager_get_connection (NMBusManager *self) +{ + g_return_val_if_fail (NM_IS_BUS_MANAGER (self), NULL); + + return NM_BUS_MANAGER_GET_PRIVATE (self)->connection; +} + +void +nm_bus_manager_register_object (NMBusManager *self, + GDBusObjectSkeleton *object) +{ + NMBusManagerPrivate *priv; + + g_return_if_fail (NM_IS_BUS_MANAGER (self)); + g_return_if_fail (NM_IS_EXPORTED_OBJECT (object)); + + priv = NM_BUS_MANAGER_GET_PRIVATE (self); + +#if NM_MORE_ASSERTS >= 1 +#if GLIB_CHECK_VERSION(2,34,0) + if (g_dbus_object_manager_server_is_exported (priv->obj_manager, object)) + g_return_if_reached (); +#endif +#endif + + g_dbus_object_manager_server_export (priv->obj_manager, object); +} + +GDBusObjectSkeleton * +nm_bus_manager_get_registered_object (NMBusManager *self, + const char *path) +{ + NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self); + + return G_DBUS_OBJECT_SKELETON (g_dbus_object_manager_get_object ((GDBusObjectManager *) priv->obj_manager, path)); +} + +void +nm_bus_manager_unregister_object (NMBusManager *self, + GDBusObjectSkeleton *object) +{ + NMBusManagerPrivate *priv; + gs_free char *path = NULL; + + g_return_if_fail (NM_IS_BUS_MANAGER (self)); + g_return_if_fail (NM_IS_EXPORTED_OBJECT (object)); + + priv = NM_BUS_MANAGER_GET_PRIVATE (self); + +#if NM_MORE_ASSERTS >= 1 +#if GLIB_CHECK_VERSION(2,34,0) + if (!g_dbus_object_manager_server_is_exported (priv->obj_manager, object)) + g_return_if_reached (); +#endif +#endif + + g_object_get (G_OBJECT (object), "g-object-path", &path, NULL); + g_return_if_fail (path != NULL); + + g_dbus_object_manager_server_unexport (priv->obj_manager, path); +} + +const char * +nm_bus_manager_connection_get_private_name (NMBusManager *self, + GDBusConnection *connection) +{ + NMBusManagerPrivate *priv; + GSList *iter; + const char *owner; + + g_return_val_if_fail (NM_IS_BUS_MANAGER (self), FALSE); + g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE); + + if (g_dbus_connection_get_unique_name (connection)) { + /* Shortcut. The connection is not a private connection. */ + return NULL; + } + + priv = NM_BUS_MANAGER_GET_PRIVATE (self); + for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) { + PrivateServer *s = iter->data; + + if ((owner = private_server_get_connection_owner (s, connection))) + return owner; + } + g_return_val_if_reached (NULL); +} + +/** + * nm_bus_manager_new_proxy: + * @self: the #NMBusManager + * @connection: the GDBusConnection for which this connection should be created + * @proxy_type: the type of #GDBusProxy to create + * @name: any name on the message bus + * @path: name of the object instance to call methods on + * @iface: name of the interface to call methods on + * + * Creates a new proxy (of type @proxy_type) for a name on a given bus. Since + * the process which called the D-Bus method could be coming from a private + * connection or the system bus connection, different proxies must be created + * for each case. This function abstracts that. + * + * Returns: a #GDBusProxy capable of calling D-Bus methods of the calling process + */ +GDBusProxy * +nm_bus_manager_new_proxy (NMBusManager *self, + GDBusConnection *connection, + GType proxy_type, + const char *name, + const char *path, + const char *iface) +{ + const char *owner; + GDBusProxy *proxy; + GError *error = NULL; + + g_return_val_if_fail (g_type_is_a (proxy_type, G_TYPE_DBUS_PROXY), NULL); + g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); + + /* Might be a private connection, for which @name is fake */ + owner = nm_bus_manager_connection_get_private_name (self, connection); + if (owner) { + g_return_val_if_fail (!g_strcmp0 (owner, name), NULL); + name = NULL; + } + + proxy = g_initable_new (proxy_type, NULL, &error, + "g-connection", connection, + "g-flags", (G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS), + "g-name", name, + "g-object-path", path, + "g-interface-name", iface, + NULL); + if (!proxy) { + nm_log_warn (LOGD_CORE, "Could not create proxy for %s on connection %s: %s", + iface, name, error->message); + g_error_free (error); + } + return proxy; +} diff --git a/src/nm-bus-manager.h b/src/nm-bus-manager.h new file mode 100644 index 00000000..8e72a3ce --- /dev/null +++ b/src/nm-bus-manager.h @@ -0,0 +1,111 @@ +/* -*- 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) 2006 - 2008 Red Hat, Inc. + * Copyright (C) 2006 - 2008 Novell, Inc. + */ + +#ifndef __NM_BUS_MANAGER_H__ +#define __NM_BUS_MANAGER_H__ + +#include "config.h" + +#include "nm-default.h" + +G_BEGIN_DECLS + +#define NM_TYPE_BUS_MANAGER (nm_bus_manager_get_type ()) +#define NM_BUS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NM_TYPE_BUS_MANAGER, NMBusManager)) +#define NM_BUS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NM_TYPE_BUS_MANAGER, NMBusManagerClass)) +#define NM_IS_BUS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NM_TYPE_BUS_MANAGER)) +#define NM_IS_BUS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NM_TYPE_BUS_MANAGER)) +#define NM_BUS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NM_TYPE_BUS_MANAGER, NMBusManagerClass)) + +#define NM_BUS_MANAGER_DBUS_CONNECTION_CHANGED "dbus-connection-changed" +#define NM_BUS_MANAGER_PRIVATE_CONNECTION_NEW "private-connection-new" +#define NM_BUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "private-connection-disconnected" + +struct _NMBusManager { + GObject parent; +}; + +typedef struct { + GObjectClass parent; + + /* Signals */ + void (*dbus_connection_changed) (NMBusManager *mgr, + GDBusConnection *connection); + + void (*private_connection_new) (NMBusManager *mgr, + GDBusConnection *connection); + + void (*private_connection_disconnected) (NMBusManager *mgr, + GDBusConnection *connection); +} NMBusManagerClass; + +GType nm_bus_manager_get_type (void); + +NMBusManager * nm_bus_manager_get (void); +void nm_bus_manager_setup (NMBusManager *instance); + +gboolean nm_bus_manager_start_service (NMBusManager *self); + +GDBusConnection * nm_bus_manager_get_connection (NMBusManager *self); + +gboolean nm_bus_manager_get_caller_info (NMBusManager *self, + GDBusMethodInvocation *context, + char **out_sender, + gulong *out_uid, + gulong *out_pid); + +const char *nm_bus_manager_connection_get_private_name (NMBusManager *self, + GDBusConnection *connection); + +gboolean nm_bus_manager_get_unix_user (NMBusManager *self, + const char *sender, + gulong *out_uid); + +gboolean nm_bus_manager_get_caller_info_from_message (NMBusManager *self, + GDBusConnection *connection, + GDBusMessage *message, + char **out_sender, + gulong *out_uid, + gulong *out_pid); + +void nm_bus_manager_register_object (NMBusManager *self, + GDBusObjectSkeleton *object); + +void nm_bus_manager_unregister_object (NMBusManager *self, + GDBusObjectSkeleton *object); + +GDBusObjectSkeleton *nm_bus_manager_get_registered_object (NMBusManager *self, + const char *path); + +void nm_bus_manager_private_server_register (NMBusManager *self, + const char *path, + const char *tag); + +GDBusProxy *nm_bus_manager_new_proxy (NMBusManager *self, + GDBusConnection *connection, + GType proxy_type, + const char *name, + const char *path, + const char *iface); + +G_END_DECLS + +#endif /* __NM_BUS_MANAGER_H__ */ diff --git a/src/nm-config-data.c b/src/nm-config-data.c index ffe00ec2..e2b6c3a6 100644 --- a/src/nm-config-data.c +++ b/src/nm-config-data.c @@ -19,17 +19,18 @@ * Copyright (C) 2013 Thomas Bechtold */ +#include "config.h" + #include "nm-config-data.h" #include #include "nm-config.h" #include "nm-device.h" -#include "gsystem-local-alloc.h" #include "nm-core-internal.h" #include "nm-keyfile-internal.h" #include "nm-macros-internal.h" -#include "nm-logging.h" +#include "nm-default.h" typedef struct { char *group_name; @@ -48,6 +49,8 @@ typedef struct { char *config_description; GKeyFile *keyfile; + GKeyFile *keyfile_user; + GKeyFile *keyfile_intern; /* A zero-terminated list of pre-processed information from the * [connection] sections. This is to speed up lookup. */ @@ -69,14 +72,34 @@ typedef struct { GSList *assume_ipv6ll_only; char *dns_mode; + char *rc_manager; + + NMGlobalDnsConfig *global_dns; + + /* mutable field */ + char *value_cached; } NMConfigDataPrivate; +struct _NMGlobalDnsDomain { + char *name; + char **servers; + char **options; +}; + +struct _NMGlobalDnsConfig { + char **searches; + char **options; + GHashTable *domains; + char **domain_list; + gboolean internal; +}; enum { PROP_0, PROP_CONFIG_MAIN_FILE, PROP_CONFIG_DESCRIPTION, - PROP_KEYFILE, + PROP_KEYFILE_USER, + PROP_KEYFILE_INTERN, PROP_CONNECTIVITY_URI, PROP_CONNECTIVITY_INTERVAL, PROP_CONNECTIVITY_RESPONSE, @@ -85,12 +108,21 @@ enum { LAST_PROP }; + G_DEFINE_TYPE (NMConfigData, nm_config_data, G_TYPE_OBJECT) #define NM_CONFIG_DATA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_CONFIG_DATA, NMConfigDataPrivate)) /************************************************************************/ +#define _HAS_PREFIX(str, prefix) \ + ({ \ + const char *_str = (str); \ + g_str_has_prefix ( _str, ""prefix"") && _str[STRLEN(prefix)] != '\0'; \ + }) + +/************************************************************************/ + const char * nm_config_data_get_config_main_file (const NMConfigData *self) { @@ -126,6 +158,22 @@ nm_config_data_get_value (const NMConfigData *self, const char *group, const cha return nm_config_keyfile_get_value (NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile, group, key, flags); } +const char *nm_config_data_get_value_cached (const NMConfigData *self, const char *group, const char *key, NMConfigGetValueFlags flags) +{ + NMConfigDataPrivate *priv; + + g_return_val_if_fail (NM_IS_CONFIG_DATA (self), NULL); + g_return_val_if_fail (group && *group, NULL); + g_return_val_if_fail (key && *key, NULL); + + priv = NM_CONFIG_DATA_GET_PRIVATE (self); + + /* we modify @value_cached. In C++ jargon, the field is mutable. */ + g_free (priv->value_cached); + priv->value_cached = nm_config_keyfile_get_value (priv->keyfile, group, key, flags); + return priv->value_cached; +} + gboolean nm_config_data_has_value (const NMConfigData *self, const char *group, const char *key, NMConfigGetValueFlags flags) { @@ -211,6 +259,14 @@ nm_config_data_get_dns_mode (const NMConfigData *self) return NM_CONFIG_DATA_GET_PRIVATE (self)->dns_mode; } +const char * +nm_config_data_get_rc_manager (const NMConfigData *self) +{ + g_return_val_if_fail (self, NULL); + + return NM_CONFIG_DATA_GET_PRIVATE (self)->rc_manager; +} + gboolean nm_config_data_get_ignore_carrier (const NMConfigData *self, NMDevice *device) { @@ -229,6 +285,40 @@ nm_config_data_get_assume_ipv6ll_only (const NMConfigData *self, NMDevice *devic return nm_device_spec_match_list (device, NM_CONFIG_DATA_GET_PRIVATE (self)->assume_ipv6ll_only); } +GKeyFile * +nm_config_data_clone_keyfile_intern (const NMConfigData *self) +{ + NMConfigDataPrivate *priv; + GKeyFile *keyfile; + + g_return_val_if_fail (NM_IS_CONFIG_DATA (self), FALSE); + + priv = NM_CONFIG_DATA_GET_PRIVATE (self); + + keyfile = nm_config_create_keyfile (); + if (priv->keyfile_intern) + _nm_keyfile_copy (keyfile, priv->keyfile_intern); + return keyfile; +} + +GKeyFile * +_nm_config_data_get_keyfile (const NMConfigData *self) +{ + return NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile; +} + +GKeyFile * +_nm_config_data_get_keyfile_intern (const NMConfigData *self) +{ + return NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile_intern; +} + +GKeyFile * +_nm_config_data_get_keyfile_user (const NMConfigData *self) +{ + return NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile_user; +} + /************************************************************************/ /** @@ -256,15 +346,128 @@ nm_config_data_get_keys (const NMConfigData *self, const char *group) return g_key_file_get_keys (NM_CONFIG_DATA_GET_PRIVATE (self)->keyfile, group, NULL, NULL); } +/** + * nm_config_data_is_intern_atomic_group: + * @self: + * @group: name of the group to check. + * + * whether a configuration group @group exists and is entirely overwritten + * by internal configuration, i.e. whether it is an atomic group that is + * overwritten. + * + * It doesn't say, that there actually is a user setting that was overwritten. That + * means there could be no corresponding section defined in user configuration + * that required overwriting. + * + * Returns: %TRUE if @group exists and is an atomic group set via internal configuration. + */ +gboolean +nm_config_data_is_intern_atomic_group (const NMConfigData *self, const char *group) +{ + NMConfigDataPrivate *priv; + + g_return_val_if_fail (NM_IS_CONFIG_DATA (self), FALSE); + g_return_val_if_fail (group && *group, FALSE); + + priv = NM_CONFIG_DATA_GET_PRIVATE (self); + + if ( !priv->keyfile_intern + || !g_key_file_has_key (priv->keyfile_intern, group, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, NULL)) + return FALSE; + + /* we have a .was entry for the section. That means that the section would be overwritten + * from user configuration. But it doesn't mean that the merged configuration contains this + * groups, because the internal setting could hide the user section. + * Only return TRUE, if we actually have such a group in the merged configuration.*/ + return g_key_file_has_group (priv->keyfile, group); +} + +/************************************************************************/ + +static GKeyFile * +_merge_keyfiles (GKeyFile *keyfile_user, GKeyFile *keyfile_intern) +{ + gs_strfreev char **groups = NULL; + guint g, k; + GKeyFile *keyfile; + gsize ngroups; + + keyfile = nm_config_create_keyfile (); + if (keyfile_user) + _nm_keyfile_copy (keyfile, keyfile_user); + if (!keyfile_intern) + return keyfile; + + groups = g_key_file_get_groups (keyfile_intern, &ngroups); + if (!groups) + return keyfile; + + /* we must reverse the order of the connection settings so that we + * have lowest priority last. */ + _nm_config_sort_groups (groups, ngroups); + for (g = 0; groups[g]; g++) { + const char *group = groups[g]; + gs_strfreev char **keys = NULL; + gboolean is_intern, is_atomic = FALSE; + + keys = g_key_file_get_keys (keyfile_intern, group, NULL, NULL); + if (!keys) + continue; + + is_intern = g_str_has_prefix (group, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN); + if ( !is_intern + && g_key_file_has_key (keyfile_intern, group, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, NULL)) { + /* the entire section is atomically overwritten by @keyfile_intern. */ + g_key_file_remove_group (keyfile, group, NULL); + is_atomic = TRUE; + } + + for (k = 0; keys[k]; k++) { + const char *key = keys[k]; + gs_free char *value = NULL; + + if (is_atomic && strcmp (key, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS) == 0) + continue; + + if ( !is_intern && !is_atomic + && _HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_WAS)) { + const char *key_base = &key[STRLEN (NM_CONFIG_KEYFILE_KEYPREFIX_WAS)]; + + if (!g_key_file_has_key (keyfile_intern, group, key_base, NULL)) + g_key_file_remove_key (keyfile, group, key_base, NULL); + continue; + } + if (!is_intern && !is_atomic && _HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_SET)) + continue; + + value = g_key_file_get_value (keyfile_intern, group, key, NULL); + g_key_file_set_value (keyfile, group, key, value); + } + } + return keyfile; +} + /************************************************************************/ static int _nm_config_data_log_sort (const char **pa, const char **pb, gpointer dummy) { gboolean a_is_connection, b_is_connection; + gboolean a_is_intern, b_is_intern; const char *a = *pa; const char *b = *pb; + /* we sort intern groups to the end. */ + a_is_intern = g_str_has_prefix (a, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN); + b_is_intern = g_str_has_prefix (b, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN); + + if (a_is_intern && b_is_intern) + return 0; + if (a_is_intern) + return 1; + if (b_is_intern) + return -1; + /* we sort connection groups before intern groups (to the end). */ a_is_connection = a && g_str_has_prefix (a, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION); b_is_connection = b && g_str_has_prefix (b, NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION); @@ -340,9 +543,12 @@ nm_config_data_log (const NMConfigData *self, for (g = 0; g < ngroups; g++) { const char *group = groups[g]; gs_strfreev char **keys = NULL; + gboolean is_atomic; + + is_atomic = nm_config_data_is_intern_atomic_group (self, group); _LOG (stream, prefix, ""); - _LOG (stream, prefix, "[%s]", group); + _LOG (stream, prefix, "[%s]%s", group, is_atomic && !stream ? " # atomic section" : ""); keys = g_key_file_get_keys (priv->keyfile, group, NULL, NULL); for (k = 0; keys && keys[k]; k++) { @@ -359,6 +565,492 @@ nm_config_data_log (const NMConfigData *self, /************************************************************************/ +const char *const * +nm_global_dns_config_get_searches (const NMGlobalDnsConfig *dns) +{ + g_return_val_if_fail (dns, NULL); + + return (const char *const *) dns->searches; +} + +const char *const * +nm_global_dns_config_get_options (const NMGlobalDnsConfig *dns) +{ + g_return_val_if_fail (dns, NULL); + + return (const char *const *) dns->options; +} + +guint +nm_global_dns_config_get_num_domains (const NMGlobalDnsConfig *dns) +{ + g_return_val_if_fail (dns, 0); + g_return_val_if_fail (dns->domains, 0); + + return g_hash_table_size (dns->domains); +} + +NMGlobalDnsDomain * +nm_global_dns_config_get_domain (const NMGlobalDnsConfig *dns, guint i) +{ + NMGlobalDnsDomain *domain; + + g_return_val_if_fail (dns, NULL); + g_return_val_if_fail (dns->domains, NULL); + g_return_val_if_fail (dns->domain_list, NULL); + g_return_val_if_fail (i < g_strv_length (dns->domain_list), NULL); + + domain = g_hash_table_lookup (dns->domains, dns->domain_list[i]); + g_return_val_if_fail (domain, NULL); + + return domain; +} + +NMGlobalDnsDomain *nm_global_dns_config_lookup_domain (const NMGlobalDnsConfig *dns, const char *name) +{ + g_return_val_if_fail (dns, NULL); + g_return_val_if_fail (dns->domains, NULL); + g_return_val_if_fail (name, NULL); + + return g_hash_table_lookup (dns->domains, name); +} + +const char * +nm_global_dns_domain_get_name (const NMGlobalDnsDomain *domain) +{ + g_return_val_if_fail (domain, NULL); + + return (const char *) domain->name; +} + +const char *const * +nm_global_dns_domain_get_servers (const NMGlobalDnsDomain *domain) +{ + g_return_val_if_fail (domain, NULL); + + return (const char *const *) domain->servers; +} + +const char *const * +nm_global_dns_domain_get_options (const NMGlobalDnsDomain *domain) +{ + g_return_val_if_fail (domain, NULL); + return (const char *const *) domain->options; +} + +gboolean +nm_global_dns_config_is_internal (const NMGlobalDnsConfig *dns) +{ + return dns->internal; +} + +gboolean +nm_global_dns_config_is_empty (const NMGlobalDnsConfig *dns) +{ + g_return_val_if_fail (dns, TRUE); + g_return_val_if_fail (dns->domains, TRUE); + + return (!dns->searches || g_strv_length (dns->searches) == 0) + && (!dns->options || g_strv_length (dns->options) == 0) + && g_hash_table_size (dns->domains) == 0; +} + +void +nm_global_dns_config_update_checksum (const NMGlobalDnsConfig *dns, GChecksum *sum) +{ + NMGlobalDnsDomain *domain; + GList *keys, *key; + guint i; + + g_return_if_fail (dns); + g_return_if_fail (dns->domains); + g_return_if_fail (sum); + + for (i = 0; dns->searches && dns->searches[i]; i++) + g_checksum_update (sum, (guchar *) dns->searches[i], strlen (dns->searches[i])); + for (i = 0; dns->options && dns->options[i]; i++) + g_checksum_update (sum, (guchar *) dns->options[i], strlen (dns->options[i])); + + keys = g_list_sort (g_hash_table_get_keys (dns->domains), (GCompareFunc) strcmp); + for (key = keys; key; key = g_list_next (key)) { + + domain = g_hash_table_lookup (dns->domains, key->data); + g_assert (domain != NULL); + g_checksum_update (sum, (guchar *) domain->name, strlen (domain->name)); + + for (i = 0; domain->servers && domain->servers[i]; i++) + g_checksum_update (sum, (guchar *) domain->servers[i], strlen (domain->servers[i])); + for (i = 0; domain->options && domain->options[i]; i++) + g_checksum_update (sum, (guchar *) domain->options[i], strlen (domain->options[i])); + } + g_list_free (keys); +} + +static void +global_dns_domain_free (NMGlobalDnsDomain *domain) +{ + if (domain) { + g_free (domain->name); + g_strfreev (domain->servers); + g_strfreev (domain->options); + g_free (domain); + } +} + +void +nm_global_dns_config_free (NMGlobalDnsConfig *conf) +{ + if (conf) { + g_strfreev (conf->searches); + g_strfreev (conf->options); + g_free (conf->domain_list); + g_hash_table_unref (conf->domains); + g_free (conf); + } +} + +NMGlobalDnsConfig * +nm_config_data_get_global_dns_config (const NMConfigData *self) +{ + g_return_val_if_fail (NM_IS_CONFIG_DATA (self), NULL); + + return NM_CONFIG_DATA_GET_PRIVATE (self)->global_dns; +} + +static void +global_dns_config_update_domain_list (NMGlobalDnsConfig *dns) +{ + guint length; + + g_free (dns->domain_list); + dns->domain_list = (char **) g_hash_table_get_keys_as_array (dns->domains, &length); +} + +static NMGlobalDnsConfig * +load_global_dns (GKeyFile *keyfile, gboolean internal) +{ + NMGlobalDnsConfig *conf; + char *group, *domain_prefix; + gs_strfreev char **groups = NULL; + int g, i, j, domain_prefix_len; + gboolean default_found = FALSE; + char **strv; + + group = internal + ? NM_CONFIG_KEYFILE_GROUP_INTERN_GLOBAL_DNS + : NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS; + domain_prefix = internal + ? NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_GLOBAL_DNS_DOMAIN + : NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN; + domain_prefix_len = strlen (domain_prefix); + + if (!nm_config_keyfile_has_global_dns_config (keyfile, internal)) + return NULL; + + conf = g_malloc0 (sizeof (NMGlobalDnsConfig)); + conf->domains = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) global_dns_domain_free); + + strv = g_key_file_get_string_list (keyfile, group, "searches", NULL, NULL); + if (strv) + conf->searches = _nm_utils_strv_cleanup (strv, TRUE, TRUE, TRUE); + + strv = g_key_file_get_string_list (keyfile, group, "options", NULL, NULL); + if (strv) { + _nm_utils_strv_cleanup (strv, TRUE, TRUE, TRUE); + for (i = 0, j = 0; strv[i]; i++) { + if (_nm_utils_dns_option_validate (strv[i], NULL, NULL, TRUE, NULL)) + strv[j++] = strv[i]; + else + g_free (strv[i]); + } + strv[j] = NULL; + conf->options = strv; + } + + groups = g_key_file_get_groups (keyfile, NULL); + for (g = 0; groups[g]; g++) { + char *name; + char **servers = NULL, **options = NULL; + NMGlobalDnsDomain *domain; + + if ( !g_str_has_prefix (groups[g], domain_prefix) + || !groups[g][domain_prefix_len]) + continue; + + strv = g_key_file_get_string_list (keyfile, groups[g], "servers", NULL, NULL); + if (strv) { + _nm_utils_strv_cleanup (strv, TRUE, TRUE, TRUE); + for (i = 0, j = 0; strv[i]; i++) { + if ( nm_utils_ipaddr_valid (AF_INET, strv[i]) + || nm_utils_ipaddr_valid (AF_INET6, strv[i])) + strv[j++] = strv[i]; + else + g_free (strv[i]); + } + if (j) { + strv[j] = NULL; + servers = strv; + } + else + g_free (strv); + } + + if (!servers) + continue; + + strv = g_key_file_get_string_list (keyfile, groups[g], "options", NULL, NULL); + if (strv) + options = _nm_utils_strv_cleanup (strv, TRUE, TRUE, TRUE); + + name = strdup (&groups[g][domain_prefix_len]); + domain = g_malloc0 (sizeof (NMGlobalDnsDomain)); + domain->name = name; + domain->servers = servers; + domain->options = options; + + g_hash_table_insert (conf->domains, strdup (name), domain); + + if (!strcmp (name, "*")) + default_found = TRUE; + } + + if (!default_found) { + nm_log_dbg (LOGD_CORE, "%s global DNS configuration is missing default domain, ignore it", + internal ? "internal" : "user"); + nm_global_dns_config_free (conf); + return NULL; + } + + conf->internal = internal; + global_dns_config_update_domain_list (conf); + return conf; +} + + +void +nm_global_dns_config_to_dbus (const NMGlobalDnsConfig *dns, GValue *value) +{ + GVariantBuilder conf_builder, domains_builder, domain_builder; + NMGlobalDnsDomain *domain; + GHashTableIter iter; + + g_variant_builder_init (&conf_builder, G_VARIANT_TYPE ("a{sv}")); + if (!dns) + goto out; + + if (dns->searches) { + g_variant_builder_add (&conf_builder, "{sv}", "searches", + g_variant_new_strv ((const char *const *) dns->searches, -1)); + } + + if (dns->options) { + g_variant_builder_add (&conf_builder, "{sv}", "options", + g_variant_new_strv ((const char *const *) dns->options, -1)); + } + + g_variant_builder_init (&domains_builder, G_VARIANT_TYPE ("a{sv}")); + + g_hash_table_iter_init (&iter, dns->domains); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &domain)) { + + g_variant_builder_init (&domain_builder, G_VARIANT_TYPE ("a{sv}")); + + if (domain->servers) { + g_variant_builder_add (&domain_builder, "{sv}", "servers", + g_variant_new_strv ((const char *const *) domain->servers, -1)); + } + if (domain->options) { + g_variant_builder_add (&domain_builder, "{sv}", "options", + g_variant_new_strv ((const char *const *) domain->options, -1)); + } + + g_variant_builder_add (&domains_builder, "{sv}", domain->name, + g_variant_builder_end (&domain_builder)); + } + + g_variant_builder_add (&conf_builder, "{sv}", "domains", + g_variant_builder_end (&domains_builder)); +out: + g_value_take_variant (value, g_variant_builder_end (&conf_builder)); +} + +static NMGlobalDnsDomain * +global_dns_domain_from_dbus (char *name, GVariant *variant) +{ + NMGlobalDnsDomain *domain; + GVariantIter iter; + char **strv, *key; + GVariant *val; + int i, j; + + if (!g_variant_is_of_type (variant, G_VARIANT_TYPE ("a{sv}"))) + return NULL; + + domain = g_malloc0 (sizeof (NMGlobalDnsDomain)); + domain->name = g_strdup (name); + + g_variant_iter_init (&iter, variant); + while (g_variant_iter_next (&iter, "{&sv}", &key, &val)) { + + if ( !g_strcmp0 (key, "servers") + && g_variant_is_of_type (val, G_VARIANT_TYPE ("as"))) { + strv = g_variant_dup_strv (val, NULL); + _nm_utils_strv_cleanup (strv, TRUE, TRUE, TRUE); + for (i = 0, j = 0; strv && strv[i]; i++) { + if ( nm_utils_ipaddr_valid (AF_INET, strv[i]) + || nm_utils_ipaddr_valid (AF_INET6, strv[i])) + strv[j++] = strv[i]; + else + g_free (strv[i]); + } + if (j) { + strv[j] = NULL; + domain->servers = strv; + } else + g_free (strv); + } else if ( !g_strcmp0 (key, "options") + && g_variant_is_of_type (val, G_VARIANT_TYPE ("as"))) { + strv = g_variant_dup_strv (val, NULL); + domain->options = _nm_utils_strv_cleanup (strv, TRUE, TRUE, TRUE); + } + + g_variant_unref (val); + } + + /* At least one server is required */ + if (!domain->servers) { + global_dns_domain_free (domain); + return NULL; + } + + return domain; +} + +NMGlobalDnsConfig * +nm_global_dns_config_from_dbus (const GValue *value, GError **error) +{ + NMGlobalDnsConfig *dns_config; + GVariant *variant, *val; + GVariantIter iter; + char **strv, *key; + int i, j; + + if (!G_VALUE_HOLDS_VARIANT (value)) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, + "invalid value type"); + return NULL; + } + + variant = g_value_get_variant (value); + if (!g_variant_is_of_type (variant, G_VARIANT_TYPE ("a{sv}"))) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, + "invalid variant type"); + return NULL; + } + + dns_config = g_malloc0 (sizeof (NMGlobalDnsConfig)); + dns_config->domains = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, (GDestroyNotify) global_dns_domain_free); + + g_variant_iter_init (&iter, variant); + while (g_variant_iter_next (&iter, "{&sv}", &key, &val)) { + + if ( !g_strcmp0 (key, "searches") + && g_variant_is_of_type (val, G_VARIANT_TYPE ("as"))) { + strv = g_variant_dup_strv (val, NULL); + dns_config->searches = _nm_utils_strv_cleanup (strv, TRUE, TRUE, TRUE); + } else if ( !g_strcmp0 (key, "options") + && g_variant_is_of_type (val, G_VARIANT_TYPE ("as"))) { + strv = g_variant_dup_strv (val, NULL); + _nm_utils_strv_cleanup (strv, TRUE, TRUE, TRUE); + + for (i = 0, j = 0; strv && strv[i]; i++) { + if (_nm_utils_dns_option_validate (strv[i], NULL, NULL, TRUE, NULL)) + strv[j++] = strv[i]; + else + g_free (strv[i]); + } + + if (strv) + strv[j] = NULL; + + dns_config->options = strv; + } else if ( !g_strcmp0 (key, "domains") + && g_variant_is_of_type (val, G_VARIANT_TYPE ("a{sv}"))) { + NMGlobalDnsDomain *domain; + GVariantIter domain_iter; + GVariant *v; + char *k; + + g_variant_iter_init (&domain_iter, val); + while (g_variant_iter_next (&domain_iter, "{&sv}", &k, &v)) { + if (k) { + domain = global_dns_domain_from_dbus (k, v); + if (domain) + g_hash_table_insert (dns_config->domains, strdup (k), domain); + } + g_variant_unref (v); + } + } + g_variant_unref (val); + } + + /* An empty value is valid and clears the internal configuration */ + if ( !nm_global_dns_config_is_empty (dns_config) + && !nm_global_dns_config_lookup_domain (dns_config, "*")) { + g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, + "Global DNS configuration is missing the default domain"); + nm_global_dns_config_free (dns_config); + return NULL; + } + + global_dns_config_update_domain_list (dns_config); + return dns_config; +} + +static gboolean +global_dns_equal (NMGlobalDnsConfig *old, NMGlobalDnsConfig *new) +{ + NMGlobalDnsDomain *domain_old, *domain_new; + gpointer key, value_old, value_new; + GHashTableIter iter; + + if (old == new) + return TRUE; + + if (!old || !new) + return FALSE; + + if ( !_nm_utils_strv_equal (old->options, new->options) + || !_nm_utils_strv_equal (old->searches, new->searches)) + return FALSE; + + if ((!old->domains || !new->domains) && old->domains != new->domains) + return FALSE; + + if (g_hash_table_size (old->domains) != g_hash_table_size (new->domains)) + return FALSE; + + g_hash_table_iter_init (&iter, old->domains); + while (g_hash_table_iter_next (&iter, &key, &value_old)) { + value_new = g_hash_table_lookup (new->domains, key); + if (!value_new) + return FALSE; + + domain_old = value_old; + domain_new = value_new; + + if ( !_nm_utils_strv_equal (domain_old->options, domain_new->options) + || !_nm_utils_strv_equal (domain_old->servers, domain_new->servers)) + return FALSE; + } + + return TRUE; +} + +/************************************************************************/ + char * nm_config_data_get_connection_default (const NMConfigData *self, const char *property, @@ -408,10 +1100,10 @@ _get_connection_info_init (ConnectionInfo *connection_info, GKeyFile *keyfile, c /* pass ownership of @group on... */ connection_info->group_name = group; - connection_info->match_device.spec = nm_config_get_device_match_spec (keyfile, - group, - "match-device", - &connection_info->match_device.has); + connection_info->match_device.spec = nm_config_get_match_spec (keyfile, + group, + "match-device", + &connection_info->match_device.has); connection_info->stop_match = nm_config_keyfile_get_boolean (keyfile, group, "stop-match", FALSE); } @@ -483,8 +1175,11 @@ nm_config_data_diff (NMConfigData *old_data, NMConfigData *new_data) priv_old = NM_CONFIG_DATA_GET_PRIVATE (old_data); priv_new = NM_CONFIG_DATA_GET_PRIVATE (new_data); - if (!_nm_keyfile_equals (priv_old->keyfile, priv_new->keyfile, TRUE)) - changes |= NM_CONFIG_CHANGE_VALUES; + if (!_nm_keyfile_equals (priv_old->keyfile_user, priv_new->keyfile_user, TRUE)) + changes |= NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER; + + if (!_nm_keyfile_equals (priv_old->keyfile_intern, priv_new->keyfile_intern, TRUE)) + changes |= NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN; if ( g_strcmp0 (nm_config_data_get_config_main_file (old_data), nm_config_data_get_config_main_file (new_data)) != 0 || g_strcmp0 (nm_config_data_get_config_description (old_data), nm_config_data_get_config_description (new_data)) != 0) @@ -502,6 +1197,12 @@ nm_config_data_diff (NMConfigData *old_data, NMConfigData *new_data) if (g_strcmp0 (nm_config_data_get_dns_mode (old_data), nm_config_data_get_dns_mode (new_data))) changes |= NM_CONFIG_CHANGE_DNS_MODE; + if (g_strcmp0 (nm_config_data_get_rc_manager (old_data), nm_config_data_get_rc_manager (new_data))) + changes |= NM_CONFIG_CHANGE_RC_MANAGER; + + if (!global_dns_equal (priv_old->global_dns, priv_new->global_dns)) + changes |= NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG; + return changes; } @@ -554,10 +1255,21 @@ set_property (GObject *object, case PROP_CONFIG_DESCRIPTION: priv->config_description = g_value_dup_string (value); break; - case PROP_KEYFILE: - priv->keyfile = g_value_dup_boxed (value); - if (!priv->keyfile) - priv->keyfile = nm_config_create_keyfile (); + case PROP_KEYFILE_USER: + priv->keyfile_user = g_value_dup_boxed (value); + if ( priv->keyfile_user + && !_nm_keyfile_has_values (priv->keyfile_user)) { + g_key_file_unref (priv->keyfile_user); + priv->keyfile_user = NULL; + } + break; + case PROP_KEYFILE_INTERN: + priv->keyfile_intern = g_value_dup_boxed (value); + if ( priv->keyfile_intern + && !_nm_keyfile_has_values (priv->keyfile_intern)) { + g_key_file_unref (priv->keyfile_intern); + priv->keyfile_intern = NULL; + } break; case PROP_NO_AUTO_DEFAULT: { @@ -607,10 +1319,13 @@ finalize (GObject *gobject) g_strfreev (priv->no_auto_default.arr); g_free (priv->dns_mode); + g_free (priv->rc_manager); g_slist_free_full (priv->ignore_carrier, g_free); g_slist_free_full (priv->assume_ipv6ll_only, g_free); + nm_global_dns_config_free (priv->global_dns); + if (priv->connection_infos) { for (i = 0; priv->connection_infos[i].group_name; i++) { g_free (priv->connection_infos[i].group_name); @@ -620,8 +1335,14 @@ finalize (GObject *gobject) } g_key_file_unref (priv->keyfile); + if (priv->keyfile_user) + g_key_file_unref (priv->keyfile_user); + if (priv->keyfile_intern) + g_key_file_unref (priv->keyfile_intern); G_OBJECT_CLASS (nm_config_data_parent_class)->finalize (gobject); + + g_free (priv->value_cached); } static void @@ -636,6 +1357,8 @@ constructed (GObject *object) NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (self); char *interval; + priv->keyfile = _merge_keyfiles (priv->keyfile_user, priv->keyfile_intern); + priv->connection_infos = _get_connection_infos (priv->keyfile); priv->connectivity.uri = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "uri", NULL)); @@ -650,11 +1373,16 @@ constructed (GObject *object) g_free (interval); priv->dns_mode = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "dns", NULL)); + priv->rc_manager = nm_strstrip (g_key_file_get_string (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "rc-manager", NULL)); + + priv->ignore_carrier = nm_config_get_match_spec (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "ignore-carrier", NULL); + priv->assume_ipv6ll_only = nm_config_get_match_spec (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "assume-ipv6ll-only", NULL); - priv->ignore_carrier = nm_config_get_device_match_spec (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "ignore-carrier", NULL); - priv->assume_ipv6ll_only = nm_config_get_device_match_spec (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "assume-ipv6ll-only", NULL); + priv->no_auto_default.specs_config = nm_config_get_match_spec (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "no-auto-default", NULL); - priv->no_auto_default.specs_config = nm_config_get_device_match_spec (priv->keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "no-auto-default", NULL); + priv->global_dns = load_global_dns (priv->keyfile_user, FALSE); + if (!priv->global_dns) + priv->global_dns = load_global_dns (priv->keyfile_intern, TRUE); G_OBJECT_CLASS (nm_config_data_parent_class)->constructed (object); } @@ -663,16 +1391,32 @@ NMConfigData * nm_config_data_new (const char *config_main_file, const char *config_description, const char *const*no_auto_default, - GKeyFile *keyfile) + GKeyFile *keyfile_user, + GKeyFile *keyfile_intern) { return g_object_new (NM_TYPE_CONFIG_DATA, NM_CONFIG_DATA_CONFIG_MAIN_FILE, config_main_file, NM_CONFIG_DATA_CONFIG_DESCRIPTION, config_description, - NM_CONFIG_DATA_KEYFILE, keyfile, + NM_CONFIG_DATA_KEYFILE_USER, keyfile_user, + NM_CONFIG_DATA_KEYFILE_INTERN, keyfile_intern, NM_CONFIG_DATA_NO_AUTO_DEFAULT, no_auto_default, NULL); } +NMConfigData * +nm_config_data_new_update_keyfile_intern (const NMConfigData *base, GKeyFile *keyfile_intern) +{ + NMConfigDataPrivate *priv = NM_CONFIG_DATA_GET_PRIVATE (base); + + return g_object_new (NM_TYPE_CONFIG_DATA, + NM_CONFIG_DATA_CONFIG_MAIN_FILE, priv->config_main_file, + NM_CONFIG_DATA_CONFIG_DESCRIPTION, priv->config_description, + NM_CONFIG_DATA_KEYFILE_USER, priv->keyfile_user, /* the keyfile is unchanged. It's safe to share it. */ + NM_CONFIG_DATA_KEYFILE_INTERN, keyfile_intern, + NM_CONFIG_DATA_NO_AUTO_DEFAULT, priv->no_auto_default.arr, + NULL); +} + NMConfigData * nm_config_data_new_update_no_auto_default (const NMConfigData *base, const char *const*no_auto_default) @@ -682,7 +1426,8 @@ nm_config_data_new_update_no_auto_default (const NMConfigData *base, return g_object_new (NM_TYPE_CONFIG_DATA, NM_CONFIG_DATA_CONFIG_MAIN_FILE, priv->config_main_file, NM_CONFIG_DATA_CONFIG_DESCRIPTION, priv->config_description, - NM_CONFIG_DATA_KEYFILE, priv->keyfile, /* the keyfile is unchanged. It's safe to share it. */ + NM_CONFIG_DATA_KEYFILE_USER, priv->keyfile_user, /* the keyfile is unchanged. It's safe to share it. */ + NM_CONFIG_DATA_KEYFILE_INTERN, priv->keyfile_intern, NM_CONFIG_DATA_NO_AUTO_DEFAULT, no_auto_default, NULL); } @@ -717,8 +1462,16 @@ nm_config_data_class_init (NMConfigDataClass *config_class) G_PARAM_STATIC_STRINGS)); g_object_class_install_property - (object_class, PROP_KEYFILE, - g_param_spec_boxed (NM_CONFIG_DATA_KEYFILE, "", "", + (object_class, PROP_KEYFILE_USER, + g_param_spec_boxed (NM_CONFIG_DATA_KEYFILE_USER, "", "", + G_TYPE_KEY_FILE, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (object_class, PROP_KEYFILE_INTERN, + g_param_spec_boxed (NM_CONFIG_DATA_KEYFILE_INTERN, "", "", G_TYPE_KEY_FILE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | diff --git a/src/nm-config-data.h b/src/nm-config-data.h index 73e789bd..2decfdb4 100644 --- a/src/nm-config-data.h +++ b/src/nm-config-data.h @@ -21,10 +21,8 @@ #ifndef NM_CONFIG_DATA_H #define NM_CONFIG_DATA_H -#include -#include -#include "nm-types.h" +#include "nm-default.h" G_BEGIN_DECLS @@ -38,7 +36,8 @@ G_BEGIN_DECLS #define NM_CONFIG_DATA_CONFIG_MAIN_FILE "config-main-file" #define NM_CONFIG_DATA_CONFIG_DESCRIPTION "config-description" -#define NM_CONFIG_DATA_KEYFILE "keyfile" +#define NM_CONFIG_DATA_KEYFILE_USER "keyfile-user" +#define NM_CONFIG_DATA_KEYFILE_INTERN "keyfile-intern" #define NM_CONFIG_DATA_CONNECTIVITY_URI "connectivity-uri" #define NM_CONFIG_DATA_CONNECTIVITY_INTERVAL "connectivity-interval" #define NM_CONFIG_DATA_CONNECTIVITY_RESPONSE "connectivity-response" @@ -71,9 +70,13 @@ typedef enum { /*< flags >*/ NM_CONFIG_CHANGE_CONFIG_FILES = (1L << 3), NM_CONFIG_CHANGE_VALUES = (1L << 4), - NM_CONFIG_CHANGE_CONNECTIVITY = (1L << 5), - NM_CONFIG_CHANGE_NO_AUTO_DEFAULT = (1L << 6), - NM_CONFIG_CHANGE_DNS_MODE = (1L << 7), + NM_CONFIG_CHANGE_VALUES_USER = (1L << 5), + NM_CONFIG_CHANGE_VALUES_INTERN = (1L << 6), + NM_CONFIG_CHANGE_CONNECTIVITY = (1L << 7), + NM_CONFIG_CHANGE_NO_AUTO_DEFAULT = (1L << 8), + NM_CONFIG_CHANGE_DNS_MODE = (1L << 9), + NM_CONFIG_CHANGE_RC_MANAGER = (1L << 10), + NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG = (1L << 11), _NM_CONFIG_CHANGE_LAST, NM_CONFIG_CHANGE_ALL = ((_NM_CONFIG_CHANGE_LAST - 1) << 1) - 1, @@ -87,12 +90,17 @@ typedef struct { GObjectClass parent; } NMConfigDataClass; +typedef struct _NMGlobalDnsConfig NMGlobalDnsConfig; +typedef struct _NMGlobalDnsDomain NMGlobalDnsDomain; + GType nm_config_data_get_type (void); NMConfigData *nm_config_data_new (const char *config_main_file, const char *config_description, const char *const*no_auto_default, - GKeyFile *keyfile); + GKeyFile *keyfile_user, + GKeyFile *keyfile_intern); +NMConfigData *nm_config_data_new_update_keyfile_intern (const NMConfigData *base, GKeyFile *keyfile_intern); NMConfigData *nm_config_data_new_update_no_auto_default (const NMConfigData *base, const char *const*no_auto_default); NMConfigChangeFlags nm_config_data_diff (NMConfigData *old_data, NMConfigData *new_data); @@ -108,6 +116,7 @@ const char *nm_config_data_get_config_description (const NMConfigData *config_da gboolean nm_config_data_has_group (const NMConfigData *self, const char *group); gboolean nm_config_data_has_value (const NMConfigData *self, const char *group, const char *key, NMConfigGetValueFlags flags); char *nm_config_data_get_value (const NMConfigData *config_data, const char *group, const char *key, NMConfigGetValueFlags flags); +const char *nm_config_data_get_value_cached (const NMConfigData *config_data, const char *group, const char *key, NMConfigGetValueFlags flags); gint nm_config_data_get_value_boolean (const NMConfigData *self, const char *group, const char *key, gint default_value); const char *nm_config_data_get_connectivity_uri (const NMConfigData *config_data); @@ -118,9 +127,11 @@ const char *const*nm_config_data_get_no_auto_default (const NMConfigData *config gboolean nm_config_data_get_no_auto_default_for_device (const NMConfigData *self, NMDevice *device); const char *nm_config_data_get_dns_mode (const NMConfigData *self); +const char *nm_config_data_get_rc_manager (const NMConfigData *self); gboolean nm_config_data_get_ignore_carrier (const NMConfigData *self, NMDevice *device); gboolean nm_config_data_get_assume_ipv6ll_only (const NMConfigData *self, NMDevice *device); +NMGlobalDnsConfig *nm_config_data_get_global_dns_config (const NMConfigData *self); char *nm_config_data_get_connection_default (const NMConfigData *self, const char *property, @@ -128,6 +139,30 @@ char *nm_config_data_get_connection_default (const NMConfigData *self, char **nm_config_data_get_groups (const NMConfigData *self); char **nm_config_data_get_keys (const NMConfigData *self, const char *group); +gboolean nm_config_data_is_intern_atomic_group (const NMConfigData *self, const char *group); + +GKeyFile *nm_config_data_clone_keyfile_intern (const NMConfigData *self); + +const char *const *nm_global_dns_config_get_searches (const NMGlobalDnsConfig *dns); +const char *const *nm_global_dns_config_get_options (const NMGlobalDnsConfig *dns); +guint nm_global_dns_config_get_num_domains (const NMGlobalDnsConfig *dns); +NMGlobalDnsDomain *nm_global_dns_config_get_domain (const NMGlobalDnsConfig *dns, guint i); +NMGlobalDnsDomain *nm_global_dns_config_lookup_domain (const NMGlobalDnsConfig *dns, const char *name); +const char *nm_global_dns_domain_get_name (const NMGlobalDnsDomain *domain); +const char *const *nm_global_dns_domain_get_servers (const NMGlobalDnsDomain *domain); +const char *const *nm_global_dns_domain_get_options (const NMGlobalDnsDomain *domain); +gboolean nm_global_dns_config_is_internal (const NMGlobalDnsConfig *dns); +gboolean nm_global_dns_config_is_empty (const NMGlobalDnsConfig *dns); +void nm_global_dns_config_update_checksum (const NMGlobalDnsConfig *dns, GChecksum *sum); +void nm_global_dns_config_free (NMGlobalDnsConfig *conf); + +NMGlobalDnsConfig *nm_global_dns_config_from_dbus (const GValue *value, GError **error); +void nm_global_dns_config_to_dbus (const NMGlobalDnsConfig *dns_config, GValue *value); + +/* private accessors */ +GKeyFile *_nm_config_data_get_keyfile (const NMConfigData *self); +GKeyFile *_nm_config_data_get_keyfile_user (const NMConfigData *self); +GKeyFile *_nm_config_data_get_keyfile_intern (const NMConfigData *self); G_END_DECLS diff --git a/src/nm-config.c b/src/nm-config.c index 561d80c1..15ef886b 100644 --- a/src/nm-config.c +++ b/src/nm-config.c @@ -24,30 +24,31 @@ #include #include +#include "nm-default.h" #include "nm-config.h" -#include "nm-logging.h" #include "nm-utils.h" -#include "nm-glib-compat.h" #include "nm-device.h" #include "NetworkManagerUtils.h" -#include "gsystem-local-alloc.h" #include "nm-enum-types.h" #include "nm-core-internal.h" - -#include -#include +#include "nm-keyfile-internal.h" #define DEFAULT_CONFIG_MAIN_FILE NMCONFDIR "/NetworkManager.conf" #define DEFAULT_CONFIG_DIR NMCONFDIR "/conf.d" #define DEFAULT_CONFIG_MAIN_FILE_OLD NMCONFDIR "/nm-system-settings.conf" +#define DEFAULT_SYSTEM_CONFIG_DIR NMLIBDIR "/conf.d" #define DEFAULT_NO_AUTO_DEFAULT_FILE NMSTATEDIR "/no-auto-default.state" +#define DEFAULT_INTERN_CONFIG_FILE NMSTATEDIR "/NetworkManager-intern.conf" struct NMConfigCmdLineOptions { char *config_main_file; + char *intern_config_file; char *config_dir; + char *system_config_dir; char *no_auto_default_file; char *plugins; gboolean configure_and_quit; + gboolean is_debug; char *connectivity_uri; /* We store interval as signed internally to track whether it's @@ -64,7 +65,9 @@ typedef struct { NMConfigData *config_data_orig; char *config_dir; + char *system_config_dir; char *no_auto_default_file; + char *intern_config_file; char **plugins; gboolean monitor_connection_files; @@ -77,11 +80,14 @@ typedef struct { char *debug; gboolean configure_and_quit; + + char **atomic_section_prefixes; } NMConfigPrivate; enum { PROP_0, PROP_CMD_LINE_OPTIONS, + PROP_ATOMIC_SECTION_PREFIXES, LAST_PROP, }; @@ -108,36 +114,19 @@ static void _set_config_data (NMConfig *self, NMConfigData *new_data, int signal /************************************************************************/ +#define _HAS_PREFIX(str, prefix) \ + ({ \ + const char *_str = (str); \ + g_str_has_prefix ( _str, ""prefix"") && _str[STRLEN(prefix)] != '\0'; \ + }) + +/************************************************************************/ + gint nm_config_parse_boolean (const char *str, gint default_value) { - gsize len; - char *s = NULL; - - if (!str) - return default_value; - - while (str[0] && g_ascii_isspace (str[0])) - str++; - - if (!str[0]) - return default_value; - - len = strlen (str); - if (g_ascii_isspace (str[len - 1])) { - s = g_strdup (str); - g_strchomp (s); - str = s; - } - - if (!g_ascii_strcasecmp (str, "true") || !g_ascii_strcasecmp (str, "yes") || !g_ascii_strcasecmp (str, "on") || !g_ascii_strcasecmp (str, "1")) - default_value = TRUE; - else if (!g_ascii_strcasecmp (str, "false") || !g_ascii_strcasecmp (str, "no") || !g_ascii_strcasecmp (str, "off") || !g_ascii_strcasecmp (str, "0")) - default_value = FALSE; - if (s) - g_free (s); - return default_value; + return nm_utils_ascii_str_to_bool (str, default_value); } gint @@ -300,6 +289,12 @@ nm_config_get_configure_and_quit (NMConfig *config) return NM_CONFIG_GET_PRIVATE (config)->configure_and_quit; } +gboolean +nm_config_get_is_debug (NMConfig *config) +{ + return NM_CONFIG_GET_PRIVATE (config)->cli.is_debug; +} + /************************************************************************/ static char ** @@ -359,7 +354,7 @@ nm_config_get_no_auto_default_for_device (NMConfig *self, NMDevice *device) void nm_config_set_no_auto_default_for_device (NMConfig *self, NMDevice *device) { - NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (self); + NMConfigPrivate *priv; GError *error = NULL; NMConfigData *new_data = NULL; const char *hw_address; @@ -370,6 +365,8 @@ nm_config_set_no_auto_default_for_device (NMConfig *self, NMDevice *device) g_return_if_fail (NM_IS_CONFIG (self)); g_return_if_fail (NM_IS_DEVICE (device)); + priv = NM_CONFIG_GET_PRIVATE (self); + hw_address = nm_device_get_hw_address (device); no_auto_default_current = nm_config_data_get_no_auto_default (priv->config_data); @@ -407,9 +404,12 @@ _nm_config_cmd_line_options_clear (NMConfigCmdLineOptions *cli) { g_clear_pointer (&cli->config_main_file, g_free); g_clear_pointer (&cli->config_dir, g_free); + g_clear_pointer (&cli->system_config_dir, g_free); g_clear_pointer (&cli->no_auto_default_file, g_free); + g_clear_pointer (&cli->intern_config_file, g_free); g_clear_pointer (&cli->plugins, g_free); cli->configure_and_quit = FALSE; + cli->is_debug = FALSE; g_clear_pointer (&cli->connectivity_uri, g_free); g_clear_pointer (&cli->connectivity_response, g_free); cli->connectivity_interval = -1; @@ -424,10 +424,13 @@ _nm_config_cmd_line_options_copy (const NMConfigCmdLineOptions *cli, NMConfigCmd _nm_config_cmd_line_options_clear (dst); dst->config_dir = g_strdup (cli->config_dir); + dst->system_config_dir = g_strdup (cli->system_config_dir); dst->config_main_file = g_strdup (cli->config_main_file); dst->no_auto_default_file = g_strdup (cli->no_auto_default_file); + dst->intern_config_file = g_strdup (cli->intern_config_file); dst->plugins = g_strdup (cli->plugins); dst->configure_and_quit = cli->configure_and_quit; + dst->is_debug = cli->is_debug; dst->connectivity_uri = g_strdup (cli->connectivity_uri); dst->connectivity_response = g_strdup (cli->connectivity_response); dst->connectivity_interval = cli->connectivity_interval; @@ -462,9 +465,12 @@ nm_config_cmd_line_options_add_to_entries (NMConfigCmdLineOptions *cli, GOptionEntry config_options[] = { { "config", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_main_file, N_("Config file location"), N_(DEFAULT_CONFIG_MAIN_FILE) }, { "config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli->config_dir, N_("Config directory location"), N_(DEFAULT_CONFIG_DIR) }, + { "system-config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli->system_config_dir, N_("System config directory location"), N_(DEFAULT_SYSTEM_CONFIG_DIR) }, + { "intern-config", 0, 0, G_OPTION_ARG_FILENAME, &cli->intern_config_file, N_("Internal config file location"), N_(DEFAULT_INTERN_CONFIG_FILE) }, { "no-auto-default", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME, &cli->no_auto_default_file, N_("State file for no-auto-default devices"), N_(DEFAULT_NO_AUTO_DEFAULT_FILE) }, { "plugins", 0, 0, G_OPTION_ARG_STRING, &cli->plugins, N_("List of plugins separated by ','"), N_(CONFIG_PLUGINS_DEFAULT) }, { "configure-and-quit", 0, 0, G_OPTION_ARG_NONE, &cli->configure_and_quit, N_("Quit after initial configuration"), NULL }, + { "debug", 'd', 0, G_OPTION_ARG_NONE, &cli->is_debug, N_("Don't become a daemon, and log to stderr"), NULL }, /* These three are hidden for now, and should eventually just go away. */ { "connectivity-uri", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_uri, N_("An http(s) address for checking internet connectivity"), "http://example.com" }, @@ -489,6 +495,47 @@ nm_config_create_keyfile () return keyfile; } +/* this is an external variable, to make loading testable. Other then that, + * no code is supposed to change this. */ +guint _nm_config_match_nm_version = NM_VERSION_CUR_STABLE; +char *_nm_config_match_env = NULL; + +static gboolean +ignore_config_snippet (GKeyFile *keyfile, gboolean is_base_config) +{ + GSList *specs; + gboolean as_bool; + NMMatchSpecMatchType match_type; + + if (is_base_config) + return FALSE; + + if (!g_key_file_has_key (keyfile, NM_CONFIG_KEYFILE_GROUP_CONFIG, NM_CONFIG_KEYFILE_KEY_CONFIG_ENABLE, NULL)) + return FALSE; + + /* first, let's try to parse the value as plain boolean. If that is possible, we don't treat + * the value as match-spec. */ + as_bool = nm_config_keyfile_get_boolean (keyfile, NM_CONFIG_KEYFILE_GROUP_CONFIG, NM_CONFIG_KEYFILE_KEY_CONFIG_ENABLE, -1); + if (as_bool != -1) + return !as_bool; + + if (G_UNLIKELY (!_nm_config_match_env)) { + const char *e; + + e = g_getenv ("NM_CONFIG_ENABLE_TAG"); + _nm_config_match_env = g_strdup (e ? e : ""); + } + + /* second, interpret the value as match-spec. */ + specs = nm_config_get_match_spec (keyfile, NM_CONFIG_KEYFILE_GROUP_CONFIG, NM_CONFIG_KEYFILE_KEY_CONFIG_ENABLE, NULL); + match_type = nm_match_spec_match_config (specs, + _nm_config_match_nm_version, + _nm_config_match_env); + g_slist_free_full (specs, g_free); + + return match_type != NM_MATCH_SPEC_MATCH; +} + static int _sort_groups_cmp (const char **pa, const char **pb, gpointer dummy) { @@ -528,6 +575,18 @@ _sort_groups_cmp (const char **pa, const char **pb, gpointer dummy) return pa > pb ? -1 : 1; } +void +_nm_config_sort_groups (char **groups, gsize ngroups) +{ + if (ngroups > 1) { + g_qsort_with_data (groups, + ngroups, + sizeof (char *), + (GCompareDataFunc) _sort_groups_cmp, + NULL); + } +} + static gboolean _setting_is_device_spec (const char *group, const char *key) { @@ -550,17 +609,23 @@ _setting_is_string_list (const char *group, const char *key) } static gboolean -read_config (GKeyFile *keyfile, const char *path, GError **error) +read_config (GKeyFile *keyfile, gboolean is_base_config, const char *dirname, const char *path, GError **error) { GKeyFile *kf; char **groups, **keys; gsize ngroups, nkeys; int g, k; + gs_free char *path_free = NULL; g_return_val_if_fail (keyfile, FALSE); g_return_val_if_fail (path, FALSE); g_return_val_if_fail (!error || !*error, FALSE); + if (dirname) { + path_free = g_build_filename (dirname, path, NULL); + path = path_free; + } + if (g_file_test (path, G_FILE_TEST_EXISTS) == FALSE) { g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND, "file %s not found", path); return FALSE; @@ -574,6 +639,16 @@ read_config (GKeyFile *keyfile, const char *path, GError **error) return FALSE; } + if (ignore_config_snippet (kf, is_base_config)) { + g_key_file_free (kf); + return TRUE; + } + + /* the config-group is internal to every configuration snippets. It doesn't make sense + * to merge the into the global configuration, and it doesn't make sense to preserve the + * group beyond this point. */ + g_key_file_remove_group (keyfile, NM_CONFIG_KEYFILE_GROUP_CONFIG, NULL); + /* Override the current settings with the new ones */ groups = g_key_file_get_groups (kf, &ngroups); if (!groups) @@ -587,17 +662,15 @@ read_config (GKeyFile *keyfile, const char *path, GError **error) * At the very end, we will revert the order of all sections again and * get thus the right behavior. This final reversing is done in * NMConfigData:_get_connection_infos(). */ - if (ngroups > 1) { - g_qsort_with_data (groups, - ngroups, - sizeof (char *), - (GCompareDataFunc) _sort_groups_cmp, - NULL); - } + _nm_config_sort_groups (groups, ngroups); for (g = 0; groups && groups[g]; g++) { const char *group = groups[g]; + if (g_str_has_prefix (group, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN)) { + /* internal groups cannot be set by user configuration. */ + continue; + } keys = g_key_file_get_keys (kf, group, &nkeys, NULL); if (!keys) continue; @@ -609,6 +682,18 @@ read_config (GKeyFile *keyfile, const char *path, GError **error) key = keys[k]; g_assert (key && *key); + + if ( _HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_WAS) + || _HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_SET)) { + /* these keys are protected. We ignore them if the user sets them. */ + continue; + } + + if (!strcmp (key, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS)) { + /* the "was" key is protected and it cannot be set by user configuration. */ + continue; + } + key_len = strlen (key); last_char = key[key_len - 1]; if ( key_len > 1 @@ -710,7 +795,7 @@ read_base_config (GKeyFile *keyfile, /* Try a user-specified config file first */ if (cli_config_main_file) { /* Bad user-specific config file path is a hard error */ - if (read_config (keyfile, cli_config_main_file, error)) { + if (read_config (keyfile, TRUE, NULL, cli_config_main_file, error)) { *out_config_main_file = g_strdup (cli_config_main_file); return TRUE; } else @@ -725,7 +810,7 @@ read_base_config (GKeyFile *keyfile, */ /* Try deprecated nm-system-settings.conf first */ - if (read_config (keyfile, DEFAULT_CONFIG_MAIN_FILE_OLD, &my_error)) { + if (read_config (keyfile, TRUE, NULL, DEFAULT_CONFIG_MAIN_FILE_OLD, &my_error)) { *out_config_main_file = g_strdup (DEFAULT_CONFIG_MAIN_FILE_OLD); return TRUE; } @@ -738,7 +823,7 @@ read_base_config (GKeyFile *keyfile, g_clear_error (&my_error); /* Try the standard config file location next */ - if (read_config (keyfile, DEFAULT_CONFIG_MAIN_FILE, &my_error)) { + if (read_config (keyfile, TRUE, NULL, DEFAULT_CONFIG_MAIN_FILE, &my_error)) { *out_config_main_file = g_strdup (DEFAULT_CONFIG_MAIN_FILE); return TRUE; } @@ -771,24 +856,20 @@ sort_asciibetically (gconstpointer a, gconstpointer b) } static GPtrArray * -_get_config_dir_files (const char *config_main_file, - const char *config_dir, - char **out_config_description) +_get_config_dir_files (const char *config_dir) { GFile *dir; GFileEnumerator *direnum; GFileInfo *info; GPtrArray *confs; - GString *config_description; const char *name; - guint i; - g_return_val_if_fail (config_main_file, NULL); g_return_val_if_fail (config_dir, NULL); - g_return_val_if_fail (out_config_description && !*out_config_description, NULL); confs = g_ptr_array_new_with_free_func (g_free); - config_description = g_string_new (config_main_file); + if (!*config_dir) + return confs; + dir = g_file_new_for_path (config_dir); direnum = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, NULL); if (direnum) { @@ -802,43 +883,59 @@ _get_config_dir_files (const char *config_main_file, } g_object_unref (dir); - if (confs->len > 0) { - g_ptr_array_sort (confs, sort_asciibetically); - g_string_append (config_description, " and conf.d: "); - for (i = 0; i < confs->len; i++) { - char *n = confs->pdata[i]; - - if (i > 0) - g_string_append (config_description, ", "); - g_string_append (config_description, n); - confs->pdata[i] = g_build_filename (config_dir, n, NULL); - g_free (n); - } - } - - *out_config_description = g_string_free (config_description, FALSE); + g_ptr_array_sort (confs, sort_asciibetically); return confs; } static GKeyFile * read_entire_config (const NMConfigCmdLineOptions *cli, const char *config_dir, + const char *system_config_dir, char **out_config_main_file, char **out_config_description, GError **error) { - GKeyFile *keyfile = nm_config_create_keyfile (); - GPtrArray *confs; + GKeyFile *keyfile; + gs_unref_ptrarray GPtrArray *system_confs = NULL; + gs_unref_ptrarray GPtrArray *confs = NULL; guint i; - char *o_config_main_file = NULL; - char *o_config_description = NULL; - char **plugins_tmp; + gs_free char *o_config_main_file = NULL; + GString *str; + char **plugins_default; g_return_val_if_fail (config_dir, NULL); - g_return_val_if_fail (out_config_main_file && !*out_config_main_file, FALSE); - g_return_val_if_fail (out_config_description && !*out_config_description, NULL); + g_return_val_if_fail (system_config_dir, NULL); + g_return_val_if_fail (!out_config_main_file || !*out_config_main_file, FALSE); + g_return_val_if_fail (!out_config_description || !*out_config_description, NULL); g_return_val_if_fail (!error || !*error, FALSE); + /* create a default configuration file. */ + keyfile = nm_config_create_keyfile (); + + plugins_default = g_strsplit (CONFIG_PLUGINS_DEFAULT, ",", -1); + if (plugins_default && plugins_default[0]) + nm_config_keyfile_set_string_list (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "plugins", (const char *const*) plugins_default, -1); + g_strfreev (plugins_default); + + system_confs = _get_config_dir_files (system_config_dir); + confs = _get_config_dir_files (config_dir); + + for (i = 0; i < system_confs->len; ) { + const char *filename = system_confs->pdata[i]; + + /* if a same named file exists in config_dir, skip it. */ + if (_nm_utils_strv_find_first ((char **) confs->pdata, confs->len, filename) >= 0) { + g_ptr_array_remove_index (system_confs, i); + continue; + } + + if (!read_config (keyfile, FALSE, system_config_dir, filename, error)) { + g_key_file_free (keyfile); + return NULL; + } + i++; + } + /* First read the base config file */ if (!read_base_config (keyfile, cli ? cli->config_main_file : NULL, &o_config_main_file, error)) { g_key_file_free (keyfile); @@ -847,33 +944,22 @@ read_entire_config (const NMConfigCmdLineOptions *cli, g_assert (o_config_main_file); - confs = _get_config_dir_files (o_config_main_file, config_dir, &o_config_description); for (i = 0; i < confs->len; i++) { - if (!read_config (keyfile, confs->pdata[i], error)) { + if (!read_config (keyfile, FALSE, config_dir, confs->pdata[i], error)) { g_key_file_free (keyfile); - g_free (o_config_main_file); - g_free (o_config_description); - g_ptr_array_unref (confs); return NULL; } } - g_ptr_array_unref (confs); /* Merge settings from command line. They overwrite everything read from * config files. */ - - if (cli && cli->plugins && cli->plugins[0]) + if (cli && cli->plugins) { + /* plugins is a string list. Set the value directly, so the user has to do proper escaping + * on the command line. */ g_key_file_set_value (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "plugins", cli->plugins); - plugins_tmp = g_key_file_get_string_list (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "plugins", NULL, NULL); - if (!plugins_tmp) { - if (STRLEN (CONFIG_PLUGINS_DEFAULT) > 0) - g_key_file_set_value (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "plugins", CONFIG_PLUGINS_DEFAULT); - } else - g_strfreev (plugins_tmp); - + } if (cli && cli->configure_and_quit) g_key_file_set_boolean (keyfile, NM_CONFIG_KEYFILE_GROUP_MAIN, "configure-and-quit", TRUE); - if (cli && cli->connectivity_uri && cli->connectivity_uri[0]) g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "uri", cli->connectivity_uri); if (cli && cli->connectivity_interval >= 0) @@ -881,13 +967,513 @@ read_entire_config (const NMConfigCmdLineOptions *cli, if (cli && cli->connectivity_response && cli->connectivity_response[0]) g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY, "response", cli->connectivity_response); - *out_config_main_file = o_config_main_file; - *out_config_description = o_config_description; + str = g_string_new (o_config_main_file); + if (system_confs->len > 0) { + for (i = 0; i < system_confs->len; i++) { + if (i == 0) + g_string_append (str, " (lib: "); + else + g_string_append (str, ", "); + g_string_append (str, system_confs->pdata[i]); + } + g_string_append (str, ")"); + } + if (confs->len > 0) { + for (i = 0; i < confs->len; i++) { + if (i == 0) + g_string_append (str, " (etc: "); + else + g_string_append (str, ", "); + g_string_append (str, confs->pdata[i]); + } + g_string_append (str, ")"); + } + + if (out_config_main_file) + *out_config_main_file = o_config_main_file; + else + g_free (o_config_main_file); + if (out_config_description) + *out_config_description = g_string_free (str, FALSE); + else + g_string_free (str, TRUE); + + o_config_main_file = NULL; return keyfile; } +static gboolean +_is_atomic_section (const char *const*atomic_section_prefixes, const char *group) +{ + if (atomic_section_prefixes) { + for (; *atomic_section_prefixes; atomic_section_prefixes++) { + if ( **atomic_section_prefixes + && g_str_has_prefix (group, *atomic_section_prefixes)) + return TRUE; + } + } + return FALSE; +} + +static void +_string_append_val (GString *str, const char *value) +{ + if (!value) + return; + g_string_append_c (str, '+'); + while (TRUE) { + switch (*value) { + case '\0': + return; + case '\\': + case '+': + case '#': + case ':': + g_string_append_c (str, '+'); + default: + g_string_append_c (str, *value); + } + value++; + } +} + +static char * +_keyfile_serialize_section (GKeyFile *keyfile, const char *group) +{ + gs_strfreev char **keys = NULL; + GString *str; + guint k; + + if (keyfile) + keys = g_key_file_get_keys (keyfile, group, NULL, NULL); + if (!keys) + return g_strdup ("0#"); + + /* prepend a version. */ + str = g_string_new ("1#"); + + for (k = 0; keys[k]; k++) { + const char *key = keys[k]; + gs_free char *value = NULL; + + _string_append_val (str, key); + g_string_append_c (str, ':'); + + value = g_key_file_get_value (keyfile, group, key, NULL); + _string_append_val (str, value); + g_string_append_c (str, '#'); + } + return g_string_free (str, FALSE); +} + +gboolean +nm_config_keyfile_has_global_dns_config (GKeyFile *keyfile, gboolean internal) +{ + gs_strfreev char **groups = NULL; + guint g; + const char *prefix; + + if (!keyfile) + return FALSE; + if (g_key_file_has_group (keyfile, + internal + ? NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS + : NM_CONFIG_KEYFILE_GROUP_INTERN_GLOBAL_DNS)) + return TRUE; + + groups = g_key_file_get_groups (keyfile, NULL); + if (!groups) + return FALSE; + + prefix = internal ? NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_GLOBAL_DNS_DOMAIN : NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN; + + for (g = 0; groups[g]; g++) { + if (g_str_has_prefix (groups[g], prefix)) + return TRUE; + } + return FALSE; +} + +/** + * intern_config_read: + * @filename: the filename where to store the internal config + * @keyfile_conf: the merged configuration from user (/etc/NM/NetworkManager.conf). + * @out_needs_rewrite: (allow-none): whether the read keyfile contains inconsistent + * data (compared to @keyfile_conf). If %TRUE, you might want to rewrite + * the file. + * + * Does the opposite of intern_config_write(). It reads the internal configuration. + * Note that the actual format of how the configuration is saved in @filename + * is different then what we return here. NMConfig manages what is written internally + * by having it inside a keyfile_intern. But we don't write that to disk as is. + * Especially, we also store parts of @keyfile_conf as ".was" and on read we compare + * what we have, with what ".was". + * + * Returns: a #GKeyFile instance with the internal configuration. + */ +static GKeyFile * +intern_config_read (const char *filename, + GKeyFile *keyfile_conf, + const char *const*atomic_section_prefixes, + gboolean *out_needs_rewrite) +{ + GKeyFile *keyfile_intern; + GKeyFile *keyfile; + gboolean needs_rewrite = FALSE; + gs_strfreev char **groups = NULL; + guint g, k; + gboolean has_intern = FALSE; + + g_return_val_if_fail (filename, NULL); + + if (!*filename) { + if (out_needs_rewrite) + *out_needs_rewrite = FALSE; + return NULL; + } + + keyfile_intern = nm_config_create_keyfile (); + + keyfile = nm_config_create_keyfile (); + if (!g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, NULL)) { + needs_rewrite = TRUE; + goto out; + } + + groups = g_key_file_get_groups (keyfile, NULL); + for (g = 0; groups && groups[g]; g++) { + gs_strfreev char **keys = NULL; + const char *group = groups[g]; + gboolean is_intern, is_atomic; + + if (!strcmp (group, NM_CONFIG_KEYFILE_GROUP_CONFIG)) + continue; + + keys = g_key_file_get_keys (keyfile, group, NULL, NULL); + if (!keys) + continue; + + is_intern = g_str_has_prefix (group, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN); + is_atomic = !is_intern && _is_atomic_section (atomic_section_prefixes, group); + + if (is_atomic) { + gs_free char *conf_section_was = NULL; + gs_free char *conf_section_is = NULL; + + conf_section_is = _keyfile_serialize_section (keyfile_conf, group); + conf_section_was = g_key_file_get_string (keyfile, group, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, NULL); + + if (g_strcmp0 (conf_section_was, conf_section_is) != 0) { + /* the section no longer matches. Skip it entirely. */ + needs_rewrite = TRUE; + continue; + } + /* we must set the "was" marker in our keyfile, so that we know that the section + * from user config is overwritten. The value doesn't matter, it's just a marker + * that this section is present. */ + g_key_file_set_value (keyfile_intern, group, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, ""); + } + + for (k = 0; keys[k]; k++) { + gs_free char *value_set = NULL; + const char *key = keys[k]; + + value_set = g_key_file_get_value (keyfile, group, key, NULL); + + if (is_intern) { + has_intern = TRUE; + g_key_file_set_value (keyfile_intern, group, key, value_set); + } else if (is_atomic) { + if (strcmp (key, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS) == 0) + continue; + g_key_file_set_value (keyfile_intern, group, key, value_set); + } else if (_HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_SET)) { + const char *key_base = &key[STRLEN (NM_CONFIG_KEYFILE_KEYPREFIX_SET)]; + gs_free char *value_was = NULL; + gs_free char *value_conf = NULL; + gs_free char *key_was = g_strdup_printf (NM_CONFIG_KEYFILE_KEYPREFIX_WAS"%s", key_base); + + if (keyfile_conf) + value_conf = g_key_file_get_value (keyfile_conf, group, key_base, NULL); + value_was = g_key_file_get_value (keyfile, group, key_was, NULL); + + if (g_strcmp0 (value_conf, value_was) != 0) { + /* if value_was is no longer the same as @value_conf, it means the user + * changed the configuration since the last write. In this case, we + * drop the value. It also means our file is out-of-date, and we should + * rewrite it. */ + needs_rewrite = TRUE; + continue; + } + has_intern = TRUE; + g_key_file_set_value (keyfile_intern, group, key_base, value_set); + } else if (_HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_WAS)) { + const char *key_base = &key[STRLEN (NM_CONFIG_KEYFILE_KEYPREFIX_WAS)]; + gs_free char *key_set = g_strdup_printf (NM_CONFIG_KEYFILE_KEYPREFIX_SET"%s", key_base); + gs_free char *value_was = NULL; + gs_free char *value_conf = NULL; + + if (g_key_file_has_key (keyfile, group, key_set, NULL)) { + /* we have a matching "set" key too. Handle the "was" key there. */ + continue; + } + + if (keyfile_conf) + value_conf = g_key_file_get_value (keyfile_conf, group, key_base, NULL); + value_was = g_key_file_get_value (keyfile, group, key, NULL); + + if (g_strcmp0 (value_conf, value_was) != 0) { + /* if value_was is no longer the same as @value_conf, it means the user + * changed the configuration since the last write. In this case, we + * don't overwrite the user-provided value. It also means our file is + * out-of-date, and we should rewrite it. */ + needs_rewrite = TRUE; + continue; + } + has_intern = TRUE; + /* signal the absence of the value. That means, we must propagate the + * "was" key to NMConfigData, so that it knows to hide the corresponding + * user key. */ + g_key_file_set_value (keyfile_intern, group, key, ""); + } else + needs_rewrite = TRUE; + } + } + +out: + /* + * If user configuration specifies global DNS options, the DNS + * options in internal configuration must be deleted. Otherwise a + * deletion of options from user configuration may cause the + * internal options to appear again. + */ + if (nm_config_keyfile_has_global_dns_config (keyfile_conf, FALSE)) { + if (g_key_file_remove_group (keyfile_intern, NM_CONFIG_KEYFILE_GROUP_INTERN_GLOBAL_DNS, NULL)) + needs_rewrite = TRUE; + for (g = 0; groups && groups[g]; g++) { + if ( g_str_has_prefix (groups[g], NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_GLOBAL_DNS_DOMAIN) + && groups[g][STRLEN (NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_GLOBAL_DNS_DOMAIN)]) { + g_key_file_remove_group (keyfile_intern, groups[g], NULL); + needs_rewrite = TRUE; + } + } + } + + g_key_file_unref (keyfile); + + if (out_needs_rewrite) + *out_needs_rewrite = needs_rewrite; + + nm_log_dbg (LOGD_CORE, "intern config file \"%s\"", filename); + + if (!has_intern) { + g_key_file_unref (keyfile_intern); + return NULL; + } + return keyfile_intern; +} + +static int +_intern_config_write_sort_fcn (const char **a, const char **b, const char *const*atomic_section_prefixes) +{ + const char *g_a = (a ? *a : NULL); + const char *g_b = (b ? *b : NULL); + gboolean a_is, b_is; + + a_is = g_str_has_prefix (g_a, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN); + b_is = g_str_has_prefix (g_b, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN); + + if (a_is != b_is) { + if (a_is) + return 1; + return -1; + } + if (!a_is) { + a_is = _is_atomic_section (atomic_section_prefixes, g_a); + b_is = _is_atomic_section (atomic_section_prefixes, g_b); + + if (a_is != b_is) { + if (a_is) + return 1; + return -1; + } + } + return g_strcmp0 (g_a, g_b); +} + +static gboolean +intern_config_write (const char *filename, + GKeyFile *keyfile_intern, + GKeyFile *keyfile_conf, + const char *const*atomic_section_prefixes, + GError **error) +{ + GKeyFile *keyfile; + gs_strfreev char **groups = NULL; + guint g, k; + gboolean has_intern = FALSE; + gboolean success = FALSE; + GError *local = NULL; + + g_return_val_if_fail (filename, FALSE); + + if (!*filename) { + g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND, "no filename to write (use --intern-config?)"); + return FALSE; + } + + keyfile = nm_config_create_keyfile (); + + if (keyfile_intern) { + groups = g_key_file_get_groups (keyfile_intern, NULL); + if (groups && groups[0]) { + g_qsort_with_data (groups, + g_strv_length (groups), + sizeof (char *), + (GCompareDataFunc) _intern_config_write_sort_fcn, + (gpointer) atomic_section_prefixes); + } + } + for (g = 0; groups && groups[g]; g++) { + gs_strfreev char **keys = NULL; + const char *group = groups[g]; + gboolean is_intern, is_atomic; + + keys = g_key_file_get_keys (keyfile_intern, group, NULL, NULL); + if (!keys) + continue; + + is_intern = g_str_has_prefix (group, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN); + is_atomic = !is_intern && _is_atomic_section (atomic_section_prefixes, group); + + if (is_atomic) { + if ( (!keys[0] || (!keys[1] && strcmp (keys[0], NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS) == 0)) + && !g_key_file_has_group (keyfile_conf, group)) { + /* we are about to save an atomic section. However, we don't have any additional + * keys on our own and there is no user-provided (overlapping) section either. + * We don't have to write an empty section (i.e. skip the useless ".was=0#"). */ + continue; + } else { + gs_free char *conf_section_is = NULL; + + conf_section_is = _keyfile_serialize_section (keyfile_conf, group); + g_key_file_set_string (keyfile, group, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, conf_section_is); + g_key_file_set_comment (keyfile, group, NULL, + " Overwrites entire section from 'NetworkManager.conf'", + NULL); + } + } + + for (k = 0; keys[k]; k++) { + const char *key = keys[k]; + gs_free char *value_set = NULL; + gs_free char *key_set = NULL; + + if ( !is_intern + && strcmp (key, NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS) == 0) { + g_warn_if_fail (is_atomic); + continue; + } + + value_set = g_key_file_get_value (keyfile_intern, group, key, NULL); + + if (is_intern) { + has_intern = TRUE; + g_key_file_set_value (keyfile, group, key, value_set); + } else if (is_atomic) + g_key_file_set_value (keyfile, group, key, value_set); + else { + gs_free char *value_was = NULL; + + if (_HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_SET)) { + /* Setting a key with .set prefix has no meaning, as these keys + * are protected. Just set the value you want to set instead. + * Why did this happen?? */ + g_warn_if_reached (); + } else if (_HAS_PREFIX (key, NM_CONFIG_KEYFILE_KEYPREFIX_WAS)) { + const char *key_base = &key[STRLEN (NM_CONFIG_KEYFILE_KEYPREFIX_WAS)]; + + if ( _HAS_PREFIX (key_base, NM_CONFIG_KEYFILE_KEYPREFIX_SET) + || _HAS_PREFIX (key_base, NM_CONFIG_KEYFILE_KEYPREFIX_WAS)) { + g_warn_if_reached (); + continue; + } + + if (g_key_file_has_key (keyfile_intern, group, key_base, NULL)) { + /* There is also a matching key_base entry. Skip processing + * the .was. key ad handle the key_base in the other else branch. */ + continue; + } + + if (keyfile_conf) { + value_was = g_key_file_get_value (keyfile_conf, group, key_base, NULL); + if (value_was) + g_key_file_set_value (keyfile, group, key, value_was); + } + } else { + if (keyfile_conf) { + value_was = g_key_file_get_value (keyfile_conf, group, key, NULL); + if (g_strcmp0 (value_set, value_was) == 0) { + /* there is no point in storing the identical value as we have via + * user configuration. Skip it. */ + continue; + } + if (value_was) { + gs_free char *key_was = NULL; + + key_was = g_strdup_printf (NM_CONFIG_KEYFILE_KEYPREFIX_WAS"%s", key); + g_key_file_set_value (keyfile, group, key_was, value_was); + } + } + key = key_set = g_strdup_printf (NM_CONFIG_KEYFILE_KEYPREFIX_SET"%s", key); + g_key_file_set_value (keyfile, group, key, value_set); + } + } + } + if ( is_intern + && g_key_file_has_group (keyfile, group)) { + g_key_file_set_comment (keyfile, group, NULL, + " Internal section. Not overwritable via user configuration in 'NetworkManager.conf'", + NULL); + } + } + + g_key_file_set_comment (keyfile, NULL, NULL, + " Internal configuration file. This file is written and read\n" + " by NetworkManager and its configuration values are merged\n" + " with the configuration from 'NetworkManager.conf'.\n" + "\n" + " Keys with a \""NM_CONFIG_KEYFILE_KEYPREFIX_SET"\" prefix specify the value to set.\n" + " A corresponding key with a \""NM_CONFIG_KEYFILE_KEYPREFIX_WAS"\" prefix records the value\n" + " of the user configuration at the time of storing the file.\n" + " The value from internal configuration is rejected if the corresponding\n" + " \""NM_CONFIG_KEYFILE_KEYPREFIX_WAS"\" key no longer matches the configuration from 'NetworkManager.conf'.\n" + " That means, if you modify a value in 'NetworkManager.conf', the internal\n" + " overwrite no longer matches and is ignored.\n" + "\n" + " Certain sections can only be overwritten whole, not on a per key basis.\n" + " Such sections are marked with a \""NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS"\" key that records the user configuration\n" + " at the time of writing.\n" + "\n" + " Internal sections of the form [" NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN "*] cannot\n" + " be set by user configuration.\n" + "\n" + " CHANGES TO THIS FILE WILL BE OVERWRITTEN", + NULL); + + success = g_key_file_save_to_file (keyfile, filename, &local); + + nm_log_dbg (LOGD_CORE, "write intern config file \"%s\"%s%s", filename, success ? "" : ": ", success ? "" : local->message); + g_key_file_unref (keyfile); + if (!success) + g_propagate_error (error, local); + return success; +} + +/************************************************************************/ + GSList * -nm_config_get_device_match_spec (const GKeyFile *keyfile, const char *group, const char *key, gboolean *out_has_key) +nm_config_get_match_spec (const GKeyFile *keyfile, const char *group, const char *key, gboolean *out_has_key) { gs_free char *value = NULL; @@ -902,16 +1488,177 @@ nm_config_get_device_match_spec (const GKeyFile *keyfile, const char *group, con /************************************************************************/ +gboolean +nm_config_set_global_dns (NMConfig *self, NMGlobalDnsConfig *global_dns, GError **error) +{ + NMConfigPrivate *priv; + GKeyFile *keyfile; + char **groups; + const NMGlobalDnsConfig *old_global_dns; + guint i; + + g_return_val_if_fail (NM_IS_CONFIG (self), FALSE); + + priv = NM_CONFIG_GET_PRIVATE (self); + g_return_val_if_fail (priv->config_data, FALSE); + + old_global_dns = nm_config_data_get_global_dns_config (priv->config_data); + if (old_global_dns && !nm_global_dns_config_is_internal (old_global_dns)) { + g_set_error_literal (error, 1, 0, + "Global DNS configuration already set via configuration file"); + return FALSE; + } + + keyfile = nm_config_data_clone_keyfile_intern (priv->config_data); + + /* Remove existing groups */ + g_key_file_remove_group (keyfile, NM_CONFIG_KEYFILE_GROUP_INTERN_GLOBAL_DNS, NULL); + groups = g_key_file_get_groups (keyfile, NULL); + for (i = 0; groups[i]; i++) { + if (g_str_has_prefix (groups[i], NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_GLOBAL_DNS_DOMAIN)) + g_key_file_remove_group (keyfile, groups[i], NULL); + } + g_strfreev (groups); + + /* An empty configuration removes everything from internal configuration file */ + if (nm_global_dns_config_is_empty (global_dns)) + goto done; + + /* Set new values */ + nm_config_keyfile_set_string_list (keyfile, NM_CONFIG_KEYFILE_GROUP_INTERN_GLOBAL_DNS, + "searches", nm_global_dns_config_get_searches (global_dns), + -1); + + nm_config_keyfile_set_string_list (keyfile, NM_CONFIG_KEYFILE_GROUP_INTERN_GLOBAL_DNS, + "options", nm_global_dns_config_get_options (global_dns), + -1); + + for (i = 0; i < nm_global_dns_config_get_num_domains (global_dns); i++) { + NMGlobalDnsDomain *domain = nm_global_dns_config_get_domain (global_dns, i); + gs_free char *group_name = NULL; + + group_name = g_strdup_printf (NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_GLOBAL_DNS_DOMAIN "%s", + nm_global_dns_domain_get_name (domain)); + + nm_config_keyfile_set_string_list (keyfile, group_name, "servers", + nm_global_dns_domain_get_servers (domain), -1); + nm_config_keyfile_set_string_list (keyfile, group_name, "options", + nm_global_dns_domain_get_options (domain), -1); + } + +done: + nm_config_set_values (self, keyfile, TRUE, FALSE); + g_key_file_unref (keyfile); + + return TRUE; +} + +/** + * nm_config_set_values: + * @self: the NMConfig instance + * @keyfile_intern_new: (allow-none): the new internal settings to set. + * If %NULL, it is equal to an empty keyfile. + * @allow_write: only if %TRUE, allow writing the changes to file. Otherwise, + * do the changes in-memory only. + * @force_rewrite: if @allow_write is %FALSE, this has no effect. If %FALSE, + * only write the configuration to file, if there are any actual changes. + * If %TRUE, always write the configuration to file, even if tere are seemingly + * no changes. + * + * This is the most flexible function to set values. It all depends on the + * keys and values you set in @keyfile_intern_new. You basically reset all + * internal configuration values to what is in @keyfile_intern_new. + * + * There are 3 types of settings: + * - all groups/sections with a prefix [.intern.*] are taken as is. As these + * groups are separate from user configuration, there is no conflict. You set + * them, that's it. + * - there are atomic sections, i.e. sections whose name start with one of + * NM_CONFIG_ATOMIC_SECTION_PREFIXES. If you put values in these sections, + * it means you completely replace the section from user configuration. + * You can also hide a user provided section by only putting the special + * key NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS into that section. + * - otherwise you can overwrite individual values from user-configuration. + * Just set the value. Keys with a prefix NM_CONFIG_KEYFILE_KEYPREFIX_* + * are protected -- as they are not value user keys. + * You can also hide a certain user setting by putting only a key + * NM_CONFIG_KEYFILE_KEYPREFIX_WAS"keyname" into the keyfile. + */ +void +nm_config_set_values (NMConfig *self, + GKeyFile *keyfile_intern_new, + gboolean allow_write, + gboolean force_rewrite) +{ + NMConfigPrivate *priv; + GKeyFile *keyfile_intern_current; + GKeyFile *keyfile_user; + GKeyFile *keyfile_new; + GError *local = NULL; + NMConfigData *new_data = NULL; + gs_strfreev char **groups = NULL; + gint g; + + g_return_if_fail (NM_IS_CONFIG (self)); + + priv = NM_CONFIG_GET_PRIVATE (self); + + keyfile_intern_current = _nm_config_data_get_keyfile_intern (priv->config_data); + + keyfile_new = nm_config_create_keyfile (); + if (keyfile_intern_new) + _nm_keyfile_copy (keyfile_new, keyfile_intern_new); + + /* ensure that every atomic section has a .was entry. */ + groups = g_key_file_get_groups (keyfile_new, NULL); + for (g = 0; groups && groups[g]; g++) { + if (_is_atomic_section ((const char *const*) priv->atomic_section_prefixes, groups[g])) + g_key_file_set_value (keyfile_new, groups[g], NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, ""); + } + + if (!_nm_keyfile_equals (keyfile_intern_current, keyfile_new, TRUE)) + new_data = nm_config_data_new_update_keyfile_intern (priv->config_data, keyfile_new); + + nm_log_dbg (LOGD_CORE, "set values(): %s", new_data ? "has changes" : "no changes"); + + if (allow_write + && (new_data || force_rewrite)) { + /* We write the internal config file based on the user configuration from + * the last load/reload. That is correct, because the intern properties might + * be in accordance to what NM thinks is currently configured. Even if the files + * on disk changed in the meantime. + * But if they changed, on the next reload with might throw away our just + * written data. That is correct, because from NM's point of view, those + * changes on disk happened in any case *after* now. */ + if (*priv->intern_config_file) { + keyfile_user = _nm_config_data_get_keyfile_user (priv->config_data); + if (!intern_config_write (priv->intern_config_file, keyfile_new, keyfile_user, + (const char *const*) priv->atomic_section_prefixes, &local)) { + nm_log_warn (LOGD_CORE, "error saving internal configuration \"%s\": %s", priv->intern_config_file, local->message); + g_clear_error (&local); + } + } else + nm_log_dbg (LOGD_CORE, "don't persistate internal configuration (no file set, use --intern-config?)"); + } + if (new_data) + _set_config_data (self, new_data, 0); + + g_key_file_unref (keyfile_new); +} + +/************************************************************************/ + void nm_config_reload (NMConfig *self, int signal) { NMConfigPrivate *priv; GError *error = NULL; - GKeyFile *keyfile; + GKeyFile *keyfile, *keyfile_intern; NMConfigData *new_data = NULL; char *config_main_file = NULL; char *config_description = NULL; gs_strfreev char **no_auto_default = NULL; + gboolean intern_config_needs_rewrite; g_return_if_fail (NM_IS_CONFIG (self)); @@ -928,6 +1675,7 @@ nm_config_reload (NMConfig *self, int signal) */ keyfile = read_entire_config (&priv->cli, priv->config_dir, + priv->system_config_dir, &config_main_file, &config_description, &error); @@ -937,58 +1685,42 @@ nm_config_reload (NMConfig *self, int signal) _set_config_data (self, NULL, signal); return; } + no_auto_default = no_auto_default_from_file (priv->no_auto_default_file); - new_data = nm_config_data_new (config_main_file, config_description, (const char *const*) no_auto_default, keyfile); + keyfile_intern = intern_config_read (priv->intern_config_file, + keyfile, + (const char *const*) priv->atomic_section_prefixes, + &intern_config_needs_rewrite); + if (intern_config_needs_rewrite) { + intern_config_write (priv->intern_config_file, keyfile_intern, keyfile, + (const char *const*) priv->atomic_section_prefixes, NULL); + } + + new_data = nm_config_data_new (config_main_file, config_description, (const char *const*) no_auto_default, keyfile, keyfile_intern); g_free (config_main_file); g_free (config_description); g_key_file_unref (keyfile); + if (keyfile_intern) + g_key_file_unref (keyfile_intern); _set_config_data (self, new_data, signal); } -static const char * -_change_flags_one_to_string (NMConfigChangeFlags flag) -{ - switch (flag) { - case NM_CONFIG_CHANGE_SIGHUP: - return "SIGHUP"; - case NM_CONFIG_CHANGE_SIGUSR1: - return "SIGUSR1"; - case NM_CONFIG_CHANGE_SIGUSR2: - return "SIGUSR2"; - case NM_CONFIG_CHANGE_CONFIG_FILES: - return "config-files"; - case NM_CONFIG_CHANGE_VALUES: - return "values"; - case NM_CONFIG_CHANGE_CONNECTIVITY: - return "connectivity"; - case NM_CONFIG_CHANGE_NO_AUTO_DEFAULT: - return "no-auto-default"; - case NM_CONFIG_CHANGE_DNS_MODE: - return "dns-mode"; - default: - g_return_val_if_reached ("unknown"); - } -} - -char * -nm_config_change_flags_to_string (NMConfigChangeFlags flags) -{ - GString *str = g_string_new (""); - NMConfigChangeFlags s = 0x01; - - while (flags) { - if (NM_FLAGS_HAS (flags, s)) { - if (str->len) - g_string_append_c (str, ','); - g_string_append (str, _change_flags_one_to_string (s)); - } - flags = flags & ~s; - s <<= 1; - } - return g_string_free (str, FALSE); -} +NM_UTILS_FLAGS2STR_DEFINE (nm_config_change_flags_to_string, NMConfigChangeFlags, + NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_SIGHUP, "SIGHUP"), + NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_SIGUSR1, "SIGUSR1"), + NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_SIGUSR2, "SIGUSR2"), + NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_CONFIG_FILES, "config-files"), + NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_VALUES, "values"), + NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_VALUES_USER, "values-user"), + NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_VALUES_INTERN, "values-intern"), + NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_CONNECTIVITY, "connectivity"), + NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_NO_AUTO_DEFAULT, "no-auto-default"), + NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_DNS_MODE, "dns-mode"), + NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_RC_MANAGER, "rc-manager"), + NM_UTILS_FLAGS2STR (NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG, "global-dns-config"), +); static void _set_config_data (NMConfig *self, NMConfigData *new_data, int signal) @@ -996,7 +1728,6 @@ _set_config_data (NMConfig *self, NMConfigData *new_data, int signal) NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (self); NMConfigData *old_data = priv->config_data; NMConfigChangeFlags changes, changes_diff; - gs_free char *log_str = NULL; gboolean had_new_data = !!new_data; switch (signal) { @@ -1027,13 +1758,13 @@ _set_config_data (NMConfig *self, NMConfigData *new_data, int signal) if (new_data) { nm_log_info (LOGD_CORE, "config: update %s (%s)", nm_config_data_get_config_description (new_data), - (log_str = nm_config_change_flags_to_string (changes))); + nm_config_change_flags_to_string (changes, NULL, 0)); nm_config_data_log (new_data, "CONFIG: ", " ", NULL); priv->config_data = new_data; } else if (had_new_data) - nm_log_info (LOGD_CORE, "config: signal %s (no changes from disk)", (log_str = nm_config_change_flags_to_string (changes))); + nm_log_info (LOGD_CORE, "config: signal %s (no changes from disk)", nm_config_change_flags_to_string (changes, NULL, 0)); else - nm_log_info (LOGD_CORE, "config: signal %s", (log_str = nm_config_change_flags_to_string (changes))); + nm_log_info (LOGD_CORE, "config: signal %s", nm_config_change_flags_to_string (changes, NULL, 0)); g_signal_emit (self, signals[SIGNAL_CONFIG_CHANGED], 0, new_data ? new_data : old_data, changes, old_data); @@ -1041,8 +1772,7 @@ _set_config_data (NMConfig *self, NMConfigData *new_data, int signal) g_object_unref (old_data); } -NM_DEFINE_SINGLETON_DESTRUCTOR (NMConfig); -NM_DEFINE_SINGLETON_WEAK_REF (NMConfig); +NM_DEFINE_SINGLETON_REGISTER (NMConfig); NMConfig * nm_config_get (void) @@ -1052,13 +1782,18 @@ nm_config_get (void) } NMConfig * -nm_config_setup (const NMConfigCmdLineOptions *cli, GError **error) +nm_config_setup (const NMConfigCmdLineOptions *cli, char **atomic_section_prefixes, GError **error) { g_assert (!singleton_instance); - singleton_instance = nm_config_new (cli, error); - if (singleton_instance) - nm_singleton_instance_weak_ref_register (); + singleton_instance = nm_config_new (cli, atomic_section_prefixes, error); + if (singleton_instance) { + nm_singleton_instance_register (); + + /* usually, you would not see this logging line because when creating the + * NMConfig instance, the logging is not yet set up to print debug message. */ + nm_log_dbg (LOGD_CORE, "setup %s singleton (%p)", "NMConfig", singleton_instance); + } return singleton_instance; } @@ -1067,10 +1802,11 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error) { NMConfig *self = NM_CONFIG (initable); NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (self); - GKeyFile *keyfile; + GKeyFile *keyfile, *keyfile_intern; char *config_main_file = NULL; char *config_description = NULL; gs_strfreev char **no_auto_default = NULL; + gboolean intern_config_needs_rewrite; if (priv->config_dir) { /* Object is already initialized. */ @@ -1085,8 +1821,26 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error) else priv->config_dir = g_strdup (DEFAULT_CONFIG_DIR); + if (priv->cli.system_config_dir) + priv->system_config_dir = g_strdup (priv->cli.system_config_dir); + else + priv->system_config_dir = g_strdup (DEFAULT_SYSTEM_CONFIG_DIR); + + if (strcmp (priv->config_dir, priv->system_config_dir) == 0) { + /* having the same directory twice makes no sense. In that case, clear + * @system_config_dir. */ + g_free (priv->system_config_dir); + priv->system_config_dir = g_strdup (""); + } + + if (priv->cli.intern_config_file) + priv->intern_config_file = g_strdup (priv->cli.intern_config_file); + else + priv->intern_config_file = g_strdup (DEFAULT_INTERN_CONFIG_FILE); + keyfile = read_entire_config (&priv->cli, priv->config_dir, + priv->system_config_dir, &config_main_file, &config_description, error); @@ -1120,23 +1874,35 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error) no_auto_default = no_auto_default_from_file (priv->no_auto_default_file); - priv->config_data_orig = nm_config_data_new (config_main_file, config_description, (const char *const*) no_auto_default, keyfile); + keyfile_intern = intern_config_read (priv->intern_config_file, + keyfile, + (const char *const*) priv->atomic_section_prefixes, + &intern_config_needs_rewrite); + if (intern_config_needs_rewrite) { + intern_config_write (priv->intern_config_file, keyfile_intern, keyfile, + (const char *const*) priv->atomic_section_prefixes, NULL); + } + + priv->config_data_orig = nm_config_data_new (config_main_file, config_description, (const char *const*) no_auto_default, keyfile, keyfile_intern); priv->config_data = g_object_ref (priv->config_data_orig); g_free (config_main_file); g_free (config_description); g_key_file_unref (keyfile); + if (keyfile_intern) + g_key_file_unref (keyfile_intern); return TRUE; } NMConfig * -nm_config_new (const NMConfigCmdLineOptions *cli, GError **error) +nm_config_new (const NMConfigCmdLineOptions *cli, char **atomic_section_prefixes, GError **error) { return NM_CONFIG (g_initable_new (NM_TYPE_CONFIG, NULL, error, NM_CONFIG_CMD_LINE_OPTIONS, cli, + NM_CONFIG_ATOMIC_SECTION_PREFIXES, atomic_section_prefixes, NULL)); } @@ -1154,12 +1920,15 @@ finalize (GObject *gobject) NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (gobject); g_free (priv->config_dir); + g_free (priv->system_config_dir); g_free (priv->no_auto_default_file); + g_free (priv->intern_config_file); g_strfreev (priv->plugins); g_free (priv->dhcp_client); g_free (priv->log_level); g_free (priv->log_domains); g_free (priv->debug); + g_strfreev (priv->atomic_section_prefixes); _nm_config_cmd_line_options_clear (&priv->cli); @@ -1186,6 +1955,10 @@ set_property (GObject *object, guint prop_id, else _nm_config_cmd_line_options_copy (cli, &priv->cli); break; + case PROP_ATOMIC_SECTION_PREFIXES: + /* construct only */ + priv->atomic_section_prefixes = g_strdupv (g_value_get_boxed (value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1208,6 +1981,14 @@ nm_config_class_init (NMConfigClass *config_class) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property + (object_class, PROP_ATOMIC_SECTION_PREFIXES, + g_param_spec_boxed (NM_CONFIG_ATOMIC_SECTION_PREFIXES, "", "", + G_TYPE_STRV, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + signals[SIGNAL_CONFIG_CHANGED] = g_signal_new (NM_CONFIG_SIGNAL_CONFIG_CHANGED, G_OBJECT_CLASS_TYPE (object_class), diff --git a/src/nm-config.h b/src/nm-config.h index 5d65e7a9..8bbab2ac 100644 --- a/src/nm-config.h +++ b/src/nm-config.h @@ -22,10 +22,8 @@ #ifndef __NETWORKMANAGER_CONFIG_H__ #define __NETWORKMANAGER_CONFIG_H__ -#include -#include -#include "nm-types.h" +#include "nm-default.h" #include "nm-config-data.h" G_BEGIN_DECLS @@ -39,6 +37,7 @@ G_BEGIN_DECLS /* Properties */ #define NM_CONFIG_CMD_LINE_OPTIONS "cmd-line-options" +#define NM_CONFIG_ATOMIC_SECTION_PREFIXES "atomic-section-prefixes" /* Signals */ #define NM_CONFIG_SIGNAL_CONFIG_CHANGED "config-changed" @@ -48,20 +47,39 @@ G_BEGIN_DECLS #define NM_CONFIG_KEYFILE_LIST_SEPARATOR ',' +#define NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN ".intern." #define NM_CONFIG_KEYFILE_GROUPPREFIX_CONNECTION "connection" +#define NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN "global-dns-domain-" #define NM_CONFIG_KEYFILE_GROUPPREFIX_TEST_APPEND_STRINGLIST ".test-append-stringlist" #define NM_CONFIG_KEYFILE_GROUP_MAIN "main" #define NM_CONFIG_KEYFILE_GROUP_LOGGING "logging" #define NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY "connectivity" +#define NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS "global-dns" +#define NM_CONFIG_KEYFILE_GROUP_CONFIG ".config" #define NM_CONFIG_KEYFILE_GROUP_KEYFILE "keyfile" #define NM_CONFIG_KEYFILE_GROUP_IFUPDOWN "ifupdown" #define NM_CONFIG_KEYFILE_GROUP_IFNET "ifnet" +#define NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND "backend" +#define NM_CONFIG_KEYFILE_KEY_CONFIG_ENABLE "enable" +#define NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS ".was" +#define NM_CONFIG_KEYFILE_KEY_KEYFILE_PATH "path" +#define NM_CONFIG_KEYFILE_KEY_KEYFILE_UNMANAGED_DEVICES "unmanaged-devices" +#define NM_CONFIG_KEYFILE_KEY_KEYFILE_HOSTNAME "hostname" #define NM_CONFIG_KEYFILE_KEY_IFNET_AUTO_REFRESH "auto_refresh" #define NM_CONFIG_KEYFILE_KEY_IFNET_MANAGED "managed" #define NM_CONFIG_KEYFILE_KEY_IFUPDOWN_MANAGED "managed" +#define NM_CONFIG_KEYFILE_KEY_AUDIT "audit" + +#define NM_CONFIG_KEYFILE_KEYPREFIX_WAS ".was." +#define NM_CONFIG_KEYFILE_KEYPREFIX_SET ".set." + +#define NM_CONFIG_KEYFILE_GROUP_INTERN_GLOBAL_DNS \ + NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN NM_CONFIG_KEYFILE_GROUP_GLOBAL_DNS +#define NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN_GLOBAL_DNS_DOMAIN \ + NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN NM_CONFIG_KEYFILE_GROUPPREFIX_GLOBAL_DNS_DOMAIN typedef struct NMConfigCmdLineOptions NMConfigCmdLineOptions; @@ -77,7 +95,7 @@ GType nm_config_get_type (void); NMConfig *nm_config_get (void); -char *nm_config_change_flags_to_string (NMConfigChangeFlags flags); +const char *nm_config_change_flags_to_string (NMConfigChangeFlags flags, char *buf, gsize len); NMConfigData *nm_config_get_data (NMConfig *config); NMConfigData *nm_config_get_data_orig (NMConfig *config); @@ -93,6 +111,12 @@ const char *nm_config_get_log_level (NMConfig *config); const char *nm_config_get_log_domains (NMConfig *config); const char *nm_config_get_debug (NMConfig *config); gboolean nm_config_get_configure_and_quit (NMConfig *config); +gboolean nm_config_get_is_debug (NMConfig *config); + +void nm_config_set_values (NMConfig *self, + GKeyFile *keyfile_intern_new, + gboolean allow_write, + gboolean force_rewrite); /* for main.c only */ NMConfigCmdLineOptions *nm_config_cmd_line_options_new (void); @@ -103,8 +127,8 @@ void nm_config_cmd_line_options_add_to_entries (NMConfigCmdLi gboolean nm_config_get_no_auto_default_for_device (NMConfig *config, NMDevice *device); void nm_config_set_no_auto_default_for_device (NMConfig *config, NMDevice *device); -NMConfig *nm_config_new (const NMConfigCmdLineOptions *cli, GError **error); -NMConfig *nm_config_setup (const NMConfigCmdLineOptions *cli, GError **error); +NMConfig *nm_config_new (const NMConfigCmdLineOptions *cli, char **atomic_section_prefixes, GError **error); +NMConfig *nm_config_setup (const NMConfigCmdLineOptions *cli, char **atomic_section_prefixes, GError **error); void nm_config_reload (NMConfig *config, int signal); gint nm_config_parse_boolean (const char *str, gint default_value); @@ -123,7 +147,17 @@ void nm_config_keyfile_set_string_list (GKeyFile *keyfile, const char *key, const char *const* strv, gssize len); -GSList *nm_config_get_device_match_spec (const GKeyFile *keyfile, const char *group, const char *key, gboolean *out_has_key); +gboolean nm_config_keyfile_has_global_dns_config (GKeyFile *keyfile, gboolean internal); + +GSList *nm_config_get_match_spec (const GKeyFile *keyfile, const char *group, const char *key, gboolean *out_has_key); + +void _nm_config_sort_groups (char **groups, gsize ngroups); + +gboolean nm_config_set_global_dns (NMConfig *self, NMGlobalDnsConfig *global_dns, GError **error); + +/* internal defines ... */ +extern guint _nm_config_match_nm_version; +extern char *_nm_config_match_env; G_END_DECLS diff --git a/src/nm-connection-provider.c b/src/nm-connection-provider.c index 51caf400..8185b8c6 100644 --- a/src/nm-connection-provider.c +++ b/src/nm-connection-provider.c @@ -18,6 +18,8 @@ #include "nm-connection-provider.h" #include "nm-utils.h" +G_DEFINE_INTERFACE (NMConnectionProvider, nm_connection_provider, G_TYPE_OBJECT) + GSList * nm_connection_provider_get_best_connections (NMConnectionProvider *self, guint max_requested, @@ -91,7 +93,7 @@ nm_connection_provider_get_connection_by_uuid (NMConnectionProvider *self, /*****************************************************************************/ static void -nm_connection_provider_init (gpointer g_iface) +nm_connection_provider_default_init (NMConnectionProviderInterface *g_iface) { GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); static gboolean initialized = FALSE; @@ -104,7 +106,7 @@ nm_connection_provider_init (gpointer g_iface) g_signal_new (NM_CP_SIGNAL_CONNECTION_ADDED, iface_type, G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMConnectionProvider, connection_added), + G_STRUCT_OFFSET (NMConnectionProviderInterface, connection_added), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); @@ -112,7 +114,7 @@ nm_connection_provider_init (gpointer g_iface) g_signal_new (NM_CP_SIGNAL_CONNECTION_UPDATED, iface_type, G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMConnectionProvider, connection_updated), + G_STRUCT_OFFSET (NMConnectionProviderInterface, connection_updated), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); @@ -120,33 +122,8 @@ nm_connection_provider_init (gpointer g_iface) g_signal_new (NM_CP_SIGNAL_CONNECTION_REMOVED, iface_type, G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMConnectionProvider, connection_removed), + G_STRUCT_OFFSET (NMConnectionProviderInterface, connection_removed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT); } - -GType -nm_connection_provider_get_type (void) -{ - static GType cp_type = 0; - - if (!G_UNLIKELY (cp_type)) { - const GTypeInfo cp_info = { - sizeof (NMConnectionProvider), /* class_size */ - nm_connection_provider_init, /* base_init */ - NULL, /* base_finalize */ - NULL, - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL - }; - - cp_type = g_type_register_static (G_TYPE_INTERFACE, "NMConnectionProvider", &cp_info, 0); - g_type_interface_add_prerequisite (cp_type, G_TYPE_OBJECT); - } - - return cp_type; -} diff --git a/src/nm-connection-provider.h b/src/nm-connection-provider.h index 8d5f7a69..2485c56f 100644 --- a/src/nm-connection-provider.h +++ b/src/nm-connection-provider.h @@ -16,15 +16,14 @@ #ifndef __NETWORKMANAGER_CONNECTION_PROVIDER_H__ #define __NETWORKMANAGER_CONNECTION_PROVIDER_H__ -#include #include -#include "nm-types.h" +#include "nm-default.h" -#define NM_TYPE_CONNECTION_PROVIDER (nm_connection_provider_get_type ()) -#define NM_CONNECTION_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CONNECTION_PROVIDER, NMConnectionProvider)) -#define NM_IS_CONNECTION_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_CONNECTION_PROVIDER)) -#define NM_CONNECTION_PROVIDER_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_CONNECTION_PROVIDER, NMConnectionProvider)) +#define NM_TYPE_CONNECTION_PROVIDER (nm_connection_provider_get_type ()) +#define NM_CONNECTION_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CONNECTION_PROVIDER, NMConnectionProvider)) +#define NM_IS_CONNECTION_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_CONNECTION_PROVIDER)) +#define NM_CONNECTION_PROVIDER_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_CONNECTION_PROVIDER, NMConnectionProviderInterface)) #define NM_CP_SIGNAL_CONNECTION_ADDED "cp-connection-added" #define NM_CP_SIGNAL_CONNECTION_UPDATED "cp-connection-updated" @@ -44,7 +43,7 @@ typedef gboolean (*NMConnectionFilterFunc) (NMConnectionProvider *provider, gpointer func_data); -struct _NMConnectionProvider { +typedef struct { GTypeInterface g_iface; /* Methods */ @@ -72,7 +71,7 @@ struct _NMConnectionProvider { void (*connection_removed) (NMConnectionProvider *self, NMConnection *connection); -}; +} NMConnectionProviderInterface; GType nm_connection_provider_get_type (void); diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c index e7e52cae..5942c5b7 100644 --- a/src/nm-connectivity.c +++ b/src/nm-connectivity.c @@ -26,11 +26,9 @@ #include #endif -#include "nm-glib-compat.h" - +#include "nm-default.h" #include "nm-connectivity.h" #include "nm-config.h" -#include "nm-logging.h" G_DEFINE_TYPE (NMConnectivity, nm_connectivity, G_TYPE_OBJECT) @@ -245,10 +243,7 @@ _reschedule_periodic_checks (NMConnectivity *self, gboolean force_reschedule) priv->initial_check_obsoleted = FALSE; } } else { - if (priv->check_id) { - g_source_remove (priv->check_id); - priv->check_id = 0; - } + nm_clear_g_source (&priv->check_id); } if (priv->check_id) return; diff --git a/src/nm-connectivity.h b/src/nm-connectivity.h index fc584d5f..f037403c 100644 --- a/src/nm-connectivity.h +++ b/src/nm-connectivity.h @@ -21,12 +21,9 @@ #ifndef __NETWORKMANAGER_CONNECTIVITY_H__ #define __NETWORKMANAGER_CONNECTIVITY_H__ -#include -#include -#include +#include "nm-default.h" #include "nm-dbus-interface.h" -#include "nm-types.h" #define NM_TYPE_CONNECTIVITY (nm_connectivity_get_type ()) #define NM_CONNECTIVITY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_CONNECTIVITY, NMConnectivity)) diff --git a/src/nm-dbus-manager.c b/src/nm-dbus-manager.c deleted file mode 100644 index 7e20b2c1..00000000 --- a/src/nm-dbus-manager.c +++ /dev/null @@ -1,998 +0,0 @@ -/* -*- 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) 2006 - 2013 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#include "config.h" - -#include -#include -#include -#include - -#include "nm-dbus-interface.h" -#include "nm-dbus-manager.h" -#include "nm-glib-compat.h" -#include "nm-properties-changed-signal.h" - -#include -#include -#include -#include -#include "nm-logging.h" -#include "NetworkManagerUtils.h" - -#define PRIV_SOCK_PATH NMRUNDIR "/private" -#define PRIV_SOCK_TAG "private" - -enum { - DBUS_CONNECTION_CHANGED = 0, - NAME_OWNER_CHANGED, - PRIVATE_CONNECTION_NEW, - PRIVATE_CONNECTION_DISCONNECTED, - NUMBER_OF_SIGNALS -}; - -static guint signals[NUMBER_OF_SIGNALS]; - -G_DEFINE_TYPE(NMDBusManager, nm_dbus_manager, G_TYPE_OBJECT) - -#define NM_DBUS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ - NM_TYPE_DBUS_MANAGER, \ - NMDBusManagerPrivate)) - -typedef struct _PrivateServer PrivateServer; - -typedef struct { - DBusConnection *connection; - DBusGConnection *g_connection; - GHashTable *exported; - gboolean started; - - GSList *private_servers; - PrivateServer *priv_server; - - DBusGProxy *proxy; - guint proxy_destroy_id; - - guint reconnect_id; -} NMDBusManagerPrivate; - -static gboolean nm_dbus_manager_init_bus (NMDBusManager *self); -static void nm_dbus_manager_cleanup (NMDBusManager *self, gboolean dispose); -static void start_reconnection_timeout (NMDBusManager *self); -static void object_destroyed (NMDBusManager *self, gpointer object); - -NM_DEFINE_SINGLETON_DESTRUCTOR (NMDBusManager); -NM_DEFINE_SINGLETON_WEAK_REF (NMDBusManager); - -NMDBusManager * -nm_dbus_manager_get (void) -{ - if (G_UNLIKELY (!singleton_instance)) { - nm_dbus_manager_setup (g_object_new (NM_TYPE_DBUS_MANAGER, NULL)); - if (!nm_dbus_manager_init_bus (singleton_instance)) - start_reconnection_timeout (singleton_instance); - } - return singleton_instance; -} - -void -nm_dbus_manager_setup (NMDBusManager *instance) -{ - static char already_setup = FALSE; - - g_assert (NM_IS_DBUS_MANAGER (instance)); - g_assert (!already_setup); - g_assert (!singleton_instance); - - already_setup = TRUE; - singleton_instance = instance; - nm_singleton_instance_weak_ref_register (); - nm_log_dbg (LOGD_CORE, "create %s singleton (%p)", "NMDBusManager", singleton_instance); -} - -/**************************************************************/ - -struct _PrivateServer { - const char *tag; - GQuark detail; - char *address; - DBusServer *server; - GHashTable *connections; - NMDBusManager *manager; -}; - -static DBusHandlerResult -private_server_message_filter (DBusConnection *conn, - DBusMessage *message, - void *data) -{ - PrivateServer *s = data; - int fd; - - /* Clean up after the connection */ - if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")) { - nm_log_dbg (LOGD_CORE, "(%s) closed connection %p on private socket (fd %d).", - s->tag, conn, dbus_connection_get_unix_fd (conn, &fd) ? fd : -1); - - /* Emit this for the manager */ - g_signal_emit (s->manager, - signals[PRIVATE_CONNECTION_DISCONNECTED], - s->detail, - dbus_connection_get_g_connection (conn)); - - g_hash_table_remove (s->connections, conn); - - /* Let dbus-glib process the message too */ - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -static dbus_bool_t -allow_only_root (DBusConnection *connection, unsigned long uid, void *data) -{ - return uid == 0; -} - -static void -private_server_new_connection (DBusServer *server, - DBusConnection *conn, - gpointer user_data) -{ - PrivateServer *s = user_data; - static guint32 counter = 0; - char *sender; - int fd; - - if (!dbus_connection_add_filter (conn, private_server_message_filter, s, NULL)) { - dbus_connection_close (conn); - return; - } - dbus_connection_set_unix_user_function (conn, allow_only_root, NULL, NULL); - dbus_connection_setup_with_g_main (conn, NULL); - - /* Fake a sender since private connections don't have one */ - sender = g_strdup_printf ("x:y:%d", counter++); - g_hash_table_insert (s->connections, dbus_connection_ref (conn), sender); - - nm_log_dbg (LOGD_CORE, "(%s) accepted connection %p on private socket (fd %d).", - s->tag, conn, dbus_connection_get_unix_fd (conn, &fd) ? fd : -1); - - /* Emit this for the manager */ - g_signal_emit (s->manager, - signals[PRIVATE_CONNECTION_NEW], - s->detail, - dbus_connection_get_g_connection (conn)); -} - -static void -private_server_dbus_connection_destroy (DBusConnection *conn) -{ - if (dbus_connection_get_is_connected (conn)) - dbus_connection_close (conn); - dbus_connection_unref (conn); -} - -static PrivateServer * -private_server_new (const char *path, - const char *tag, - NMDBusManager *manager) -{ - PrivateServer *s; - DBusServer *server; - DBusError error; - char *address; - - unlink (path); - address = g_strdup_printf ("unix:path=%s", path); - - nm_log_dbg (LOGD_CORE, "(%s) creating private socket %s.", tag, address); - - dbus_error_init (&error); - server = dbus_server_listen (address, &error); - if (!server) { - nm_log_warn (LOGD_CORE, "(%s) failed to set up private socket %s: %s", - tag, address, error.message); - dbus_error_free (&error); - g_free (address); - return NULL; - } - - s = g_malloc0 (sizeof (*s)); - s->address = address; - s->server = server; - dbus_server_setup_with_g_main (s->server, NULL); - dbus_server_set_new_connection_function (s->server, private_server_new_connection, s, NULL); - - s->connections = g_hash_table_new_full (g_direct_hash, g_direct_equal, - (GDestroyNotify) private_server_dbus_connection_destroy, - g_free); - s->manager = manager; - s->detail = g_quark_from_string (tag); - s->tag = g_quark_to_string (s->detail); - - return s; -} - -static void -private_server_free (gpointer ptr) -{ - PrivateServer *s = ptr; - - unlink (s->address); - g_free (s->address); - g_hash_table_destroy (s->connections); - dbus_server_unref (s->server); - memset (s, 0, sizeof (*s)); - g_free (s); -} - -void -nm_dbus_manager_private_server_register (NMDBusManager *self, - const char *path, - const char *tag) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - PrivateServer *s; - GSList *iter; - -#if !HAVE_DBUS_GLIB_100 - g_assert_not_reached (); -#endif - - g_return_if_fail (self != NULL); - g_return_if_fail (path != NULL); - g_return_if_fail (tag != NULL); - - /* Only one instance per tag; but don't warn */ - for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) { - s = iter->data; - if (g_strcmp0 (tag, s->tag) == 0) - return; - } - - s = private_server_new (path, tag, self); - if (s) - priv->private_servers = g_slist_append (priv->private_servers, s); -} - -static const char * -private_server_get_connection_owner (PrivateServer *s, DBusGConnection *connection) -{ - g_return_val_if_fail (s != NULL, NULL); - g_return_val_if_fail (connection != NULL, NULL); - - return g_hash_table_lookup (s->connections, dbus_g_connection_get_connection (connection)); -} - -/**************************************************************/ - -static gboolean -_bus_get_unix_pid (NMDBusManager *self, - const char *sender, - gulong *out_pid, - GError **error) -{ - guint32 unix_pid = G_MAXUINT32; - - if (!dbus_g_proxy_call_with_timeout (NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy, - "GetConnectionUnixProcessID", 2000, error, - G_TYPE_STRING, sender, - G_TYPE_INVALID, - G_TYPE_UINT, &unix_pid, - G_TYPE_INVALID)) { - return FALSE; - } - - *out_pid = (gulong) unix_pid; - return TRUE; -} - -/** - * _get_caller_info_from_context(): - * - * Given a dbus-glib method invocation, or a DBusConnection + DBusMessage, - * return the sender and the UID of the sender. - */ -static gboolean -_get_caller_info (NMDBusManager *self, - DBusGMethodInvocation *context, - DBusConnection *connection, - DBusMessage *message, - char **out_sender, - gulong *out_uid, - gulong *out_pid) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - DBusGConnection *gconn; - char *sender; - const char *priv_sender; - DBusError error; - GSList *iter; - - if (context) { - gconn = dbus_g_method_invocation_get_g_connection (context); - g_assert (gconn); - connection = dbus_g_connection_get_connection (gconn); - - /* only bus connections will have a sender */ - sender = dbus_g_method_get_sender (context); - } else { - g_assert (message); - sender = g_strdup (dbus_message_get_sender (message)); - } - g_assert (connection); - - if (!sender) { - /* Might be a private connection, for which we fake a sender */ - for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) { - PrivateServer *s = iter->data; - - priv_sender = g_hash_table_lookup (s->connections, connection); - if (priv_sender) { - if (out_uid) - *out_uid = 0; - if (out_sender) - *out_sender = g_strdup (priv_sender); - if (out_pid) { - if (!dbus_connection_get_unix_process_id (connection, out_pid)) - *out_pid = G_MAXULONG; - } - return TRUE; - } - } - return FALSE; - } - - /* Bus connections always have a sender */ - g_assert (sender); - if (out_uid) { - dbus_error_init (&error); - *out_uid = dbus_bus_get_unix_user (connection, sender, &error); - if (dbus_error_is_set (&error)) { - dbus_error_free (&error); - *out_uid = G_MAXULONG; - g_free (sender); - return FALSE; - } - } - - if (out_pid) { - if (!_bus_get_unix_pid (self, sender, out_pid, NULL)) { - *out_pid = G_MAXULONG; - g_free (sender); - return FALSE; - } - } - - if (out_sender) - *out_sender = g_strdup (sender); - - g_free (sender); - return TRUE; -} - -gboolean -nm_dbus_manager_get_caller_info (NMDBusManager *self, - DBusGMethodInvocation *context, - char **out_sender, - gulong *out_uid, - gulong *out_pid) -{ - return _get_caller_info (self, context, NULL, NULL, out_sender, out_uid, out_pid); -} - -gboolean -nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self, - DBusConnection *connection, - DBusMessage *message, - char **out_sender, - gulong *out_uid, - gulong *out_pid) -{ - return _get_caller_info (self, NULL, connection, message, out_sender, out_uid, out_pid); -} - -gboolean -nm_dbus_manager_get_unix_user (NMDBusManager *self, - const char *sender, - gulong *out_uid) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - GSList *iter; - DBusError error; - - g_return_val_if_fail (sender != NULL, FALSE); - g_return_val_if_fail (out_uid != NULL, FALSE); - - /* Check if it's a private connection sender, which we fake */ - for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) { - PrivateServer *s = iter->data; - GHashTableIter hiter; - const char *priv_sender; - - g_hash_table_iter_init (&hiter, s->connections); - while (g_hash_table_iter_next (&hiter, NULL, (gpointer) &priv_sender)) { - if (g_strcmp0 (sender, priv_sender) == 0) { - *out_uid = 0; - return TRUE; - } - } - } - - /* Otherwise, a bus connection */ - dbus_error_init (&error); - *out_uid = dbus_bus_get_unix_user (priv->connection, sender, &error); - if (dbus_error_is_set (&error)) { - nm_log_warn (LOGD_CORE, "Failed to get unix user for dbus sender '%s': %s", - sender, error.message); - return FALSE; - } - - return TRUE; -} - -/**************************************************************/ - -#if HAVE_DBUS_GLIB_100 -static void -private_connection_new (NMDBusManager *self, DBusGConnection *connection) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - GHashTableIter iter; - GObject *object; - const char *path; - - /* Register all exported objects on this private connection */ - g_hash_table_iter_init (&iter, priv->exported); - while (g_hash_table_iter_next (&iter, (gpointer) &object, (gpointer) &path)) { - dbus_g_connection_register_g_object (connection, path, object); - nm_log_trace (LOGD_CORE, "(%s) registered %p (%s) at '%s' on private socket.", - PRIV_SOCK_TAG, object, G_OBJECT_TYPE_NAME (object), path); - } -} - -static void -private_connection_disconnected (NMDBusManager *self, DBusGConnection *connection) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - const char *owner; - - owner = private_server_get_connection_owner (priv->priv_server, connection); - g_assert (owner); - - /* Fake a NameOwnerChanged to let listerners know this owner has quit */ - g_signal_emit (G_OBJECT (self), signals[NAME_OWNER_CHANGED], - 0, owner, owner, NULL); -} - -static void -private_server_setup (NMDBusManager *self) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - /* Skip this step if this is just a test program */ - if (nm_utils_get_testing ()) - return; - - /* Set up our main private DBus socket */ - if (mkdir (NMRUNDIR, 0700) == -1) { - if (errno != EEXIST) - nm_log_warn (LOGD_CORE, "Error creating directory \"%s\": %d (%s)", NMRUNDIR, errno, g_strerror (errno)); - } - priv->priv_server = private_server_new (PRIV_SOCK_PATH, PRIV_SOCK_TAG, self); - if (priv->priv_server) { - priv->private_servers = g_slist_append (priv->private_servers, priv->priv_server); - - g_signal_connect (self, - NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW "::" PRIV_SOCK_TAG, - (GCallback) private_connection_new, - NULL); - g_signal_connect (self, - NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "::" PRIV_SOCK_TAG, - (GCallback) private_connection_disconnected, - NULL); - } -} -#endif /* HAVE_DBUS_GLIB_100 */ - -static void -nm_dbus_manager_init (NMDBusManager *self) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - priv->exported = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); - -#if HAVE_DBUS_GLIB_100 - private_server_setup (self); -#endif -} - -static void -nm_dbus_manager_dispose (GObject *object) -{ - NMDBusManager *self = NM_DBUS_MANAGER (object); - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - GHashTableIter iter; - GObject *exported; - - if (priv->exported) { - g_hash_table_iter_init (&iter, priv->exported); - while (g_hash_table_iter_next (&iter, (gpointer) &exported, NULL)) - g_object_weak_unref (exported, (GWeakNotify) object_destroyed, self); - - g_hash_table_destroy (priv->exported); - priv->exported = NULL; - } - - g_slist_free_full (priv->private_servers, private_server_free); - priv->private_servers = NULL; - priv->priv_server = NULL; - - nm_dbus_manager_cleanup (self, TRUE); - - if (priv->reconnect_id) { - g_source_remove (priv->reconnect_id); - priv->reconnect_id = 0; - } - - G_OBJECT_CLASS (nm_dbus_manager_parent_class)->dispose (object); -} - -static void -nm_dbus_manager_class_init (NMDBusManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (NMDBusManagerPrivate)); - - object_class->dispose = nm_dbus_manager_dispose; - - signals[DBUS_CONNECTION_CHANGED] = - g_signal_new (NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMDBusManagerClass, dbus_connection_changed), - NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_POINTER); - - signals[NAME_OWNER_CHANGED] = - g_signal_new (NM_DBUS_MANAGER_NAME_OWNER_CHANGED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMDBusManagerClass, name_owner_changed), - NULL, NULL, NULL, - G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); - - signals[PRIVATE_CONNECTION_NEW] = - g_signal_new (NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - G_STRUCT_OFFSET (NMDBusManagerClass, private_connection_new), - NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_POINTER); - - signals[PRIVATE_CONNECTION_DISCONNECTED] = - g_signal_new (NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - G_STRUCT_OFFSET (NMDBusManagerClass, private_connection_disconnected), - NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_POINTER); -} - - -/* Only cleanup a specific dbus connection, not all our private data */ -static void -nm_dbus_manager_cleanup (NMDBusManager *self, gboolean dispose) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - if (priv->proxy) { - if (dispose) { - g_signal_handler_disconnect (priv->proxy, priv->proxy_destroy_id); - priv->proxy_destroy_id = 0; - } - g_object_unref (priv->proxy); - priv->proxy = NULL; - } - - if (priv->g_connection) { - dbus_g_connection_unref (priv->g_connection); - priv->g_connection = NULL; - priv->connection = NULL; - } - - priv->started = FALSE; -} - -static gboolean -nm_dbus_manager_reconnect (gpointer user_data) -{ - NMDBusManager *self = NM_DBUS_MANAGER (user_data); - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - g_assert (self != NULL); - - if (nm_dbus_manager_init_bus (self)) { - if (nm_dbus_manager_start_service (self)) { - nm_log_info (LOGD_CORE, "reconnected to the system bus."); - g_signal_emit (self, signals[DBUS_CONNECTION_CHANGED], - 0, priv->connection); - priv->reconnect_id = 0; - return FALSE; - } - } - - /* Try again */ - nm_dbus_manager_cleanup (self, FALSE); - return TRUE; -} - -static void -start_reconnection_timeout (NMDBusManager *self) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - if (priv->reconnect_id) - g_source_remove (priv->reconnect_id); - - /* Schedule timeout for reconnection attempts */ - priv->reconnect_id = g_timeout_add_seconds (3, nm_dbus_manager_reconnect, self); -} - -char * -nm_dbus_manager_get_name_owner (NMDBusManager *self, - const char *name, - GError **error) -{ - char *owner = NULL; - - g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), NULL); - g_return_val_if_fail (name != NULL, NULL); - if (error) - g_return_val_if_fail (*error == NULL, NULL); - - if (!NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy) - return NULL; - - if (!dbus_g_proxy_call_with_timeout (NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy, - "GetNameOwner", 2000, error, - G_TYPE_STRING, name, - G_TYPE_INVALID, - G_TYPE_STRING, &owner, - G_TYPE_INVALID)) { - return NULL; - } - - return owner; -} - -gboolean -nm_dbus_manager_name_has_owner (NMDBusManager *self, - const char *name) -{ - gboolean has_owner = FALSE; - GError *err = NULL; - - g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), FALSE); - g_return_val_if_fail (name != NULL, FALSE); - - if (!NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy) - return FALSE; - - if (!dbus_g_proxy_call (NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy, - "NameHasOwner", &err, - G_TYPE_STRING, name, - G_TYPE_INVALID, - G_TYPE_BOOLEAN, &has_owner, - G_TYPE_INVALID)) { - nm_log_warn (LOGD_CORE, "NameHasOwner request failed: %s", - (err && err->message) ? err->message : "(unknown)"); - g_clear_error (&err); - } - - return has_owner; -} - -static void -proxy_name_owner_changed (DBusGProxy *proxy, - const char *name, - const char *old_owner, - const char *new_owner, - gpointer user_data) -{ - g_signal_emit (G_OBJECT (user_data), signals[NAME_OWNER_CHANGED], - 0, name, old_owner, new_owner); -} - -static void -destroy_cb (DBusGProxy *proxy, gpointer user_data) -{ - NMDBusManager *self = NM_DBUS_MANAGER (user_data); - - /* Clean up existing connection */ - nm_log_warn (LOGD_CORE, "disconnected by the system bus."); - NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy = NULL; - - nm_dbus_manager_cleanup (self, FALSE); - - g_signal_emit (G_OBJECT (self), signals[DBUS_CONNECTION_CHANGED], 0, NULL); - - start_reconnection_timeout (self); -} - -static gboolean -nm_dbus_manager_init_bus (NMDBusManager *self) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - if (priv->connection) { - nm_log_warn (LOGD_CORE, "DBus Manager already has a valid connection."); - return FALSE; - } - - dbus_connection_set_change_sigpipe (TRUE); - - priv->g_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL); - if (!priv->g_connection) { - /* Log with 'info' severity; there won't be a bus daemon in minimal - * environments (eg, initrd) where we only want to use the private - * socket. - */ - nm_log_info (LOGD_CORE, "Could not connect to the system bus; only the " - "private D-Bus socket will be available."); - return FALSE; - } - - priv->connection = dbus_g_connection_get_connection (priv->g_connection); - dbus_connection_set_exit_on_disconnect (priv->connection, FALSE); - - priv->proxy = dbus_g_proxy_new_for_name (priv->g_connection, - "org.freedesktop.DBus", - "/org/freedesktop/DBus", - "org.freedesktop.DBus"); - - priv->proxy_destroy_id = g_signal_connect (priv->proxy, "destroy", - G_CALLBACK (destroy_cb), self); - - dbus_g_proxy_add_signal (priv->proxy, "NameOwnerChanged", - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, - "NameOwnerChanged", - G_CALLBACK (proxy_name_owner_changed), - self, NULL); - return TRUE; -} - -/* Register our service on the bus; shouldn't be called until - * all necessary message handlers have been registered, because - * when we register on the bus, clients may start to call. - */ -gboolean -nm_dbus_manager_start_service (NMDBusManager *self) -{ - NMDBusManagerPrivate *priv; - int result; - GError *err = NULL; - - g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), FALSE); - - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - if (priv->started) { - nm_log_err (LOGD_CORE, "Service has already started."); - return FALSE; - } - - /* Pointless to request a name when we aren't connected to the bus */ - if (!priv->proxy) - return FALSE; - - if (!dbus_g_proxy_call (priv->proxy, "RequestName", &err, - G_TYPE_STRING, NM_DBUS_SERVICE, - G_TYPE_UINT, DBUS_NAME_FLAG_DO_NOT_QUEUE, - G_TYPE_INVALID, - G_TYPE_UINT, &result, - G_TYPE_INVALID)) { - nm_log_err (LOGD_CORE, "Could not acquire the NetworkManager service.\n" - " Error: '%s'", - (err && err->message) ? err->message : "(unknown)"); - g_error_free (err); - return FALSE; - } - - if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { - nm_log_err (LOGD_CORE, "Could not acquire the NetworkManager service as it is already taken."); - return FALSE; - } - - priv->started = TRUE; - return priv->started; -} - -DBusConnection * -nm_dbus_manager_get_dbus_connection (NMDBusManager *self) -{ - g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), NULL); - - return NM_DBUS_MANAGER_GET_PRIVATE (self)->connection; -} - -DBusGConnection * -nm_dbus_manager_get_connection (NMDBusManager *self) -{ - g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), NULL); - - return NM_DBUS_MANAGER_GET_PRIVATE (self)->g_connection; -} - -static void -object_destroyed (NMDBusManager *self, gpointer object) -{ - g_hash_table_remove (NM_DBUS_MANAGER_GET_PRIVATE (self)->exported, object); -} - -void -nm_dbus_manager_register_exported_type (NMDBusManager *self, - GType object_type, - const DBusGObjectInfo *info) -{ - const char *properties_info, *dbus_name, *gobject_name, *tmp_access; - - dbus_g_object_type_install_info (object_type, info); - if (!info->exported_properties) - return; - - properties_info = info->exported_properties; - while (*properties_info) { - /* The format is: "interface\0DBusPropertyName\0gobject_property_name\0access\0" */ - dbus_name = strchr (properties_info, '\0') + 1; - gobject_name = strchr (dbus_name, '\0') + 1; - tmp_access = strchr (gobject_name, '\0') + 1; - properties_info = strchr (tmp_access, '\0') + 1; - - /* Note that nm-properties-changed-signal takes advantage of the - * fact that @dbus_name and @gobject_name are static data that won't - * ever be freed. - */ - nm_properties_changed_signal_add_property (object_type, dbus_name, gobject_name); - } -} - -void -nm_dbus_manager_register_object (NMDBusManager *self, - const char *path, - gpointer object) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - GHashTableIter iter; - DBusConnection *connection; - - g_assert (G_IS_OBJECT (object)); - - if (g_hash_table_lookup (priv->exported, G_OBJECT (object))) - g_return_if_reached (); - - g_hash_table_insert (priv->exported, G_OBJECT (object), g_strdup (path)); - g_object_weak_ref (G_OBJECT (object), (GWeakNotify) object_destroyed, self); - - if (priv->g_connection) - dbus_g_connection_register_g_object (priv->g_connection, path, G_OBJECT (object)); - - if (priv->priv_server) { - g_hash_table_iter_init (&iter, priv->priv_server->connections); - while (g_hash_table_iter_next (&iter, (gpointer) &connection, NULL)) { - dbus_g_connection_register_g_object (dbus_connection_get_g_connection (connection), - path, - G_OBJECT (object)); - } - } -} - -void -nm_dbus_manager_unregister_object (NMDBusManager *self, gpointer object) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - GHashTableIter iter; - DBusConnection *connection; - - g_assert (G_IS_OBJECT (object)); - - if (!g_hash_table_lookup (priv->exported, G_OBJECT (object))) - g_return_if_reached (); - - g_hash_table_remove (priv->exported, G_OBJECT (object)); - g_object_weak_unref (G_OBJECT (object), (GWeakNotify) object_destroyed, self); - - if (priv->g_connection) - dbus_g_connection_unregister_g_object (priv->g_connection, G_OBJECT (object)); - - if (priv->priv_server) { - g_hash_table_iter_init (&iter, priv->priv_server->connections); - while (g_hash_table_iter_next (&iter, (gpointer) &connection, NULL)) { - dbus_g_connection_unregister_g_object (dbus_connection_get_g_connection (connection), - G_OBJECT (object)); - } - } -} - -/** - * nm_dbus_manager_new_proxy: - * @self: the #NMDBusManager - * @context: the method call context this proxy should be created - * @name: any name on the message bus - * @path: name of the object instance to call methods on - * @iface: name of the interface to call methods on - * - * Creates a new proxy for a name on a given bus. Since the process which - * called the D-Bus method could be coming from a private connection or the - * system bus connection, differnet proxies must be created for each case. This - * function abstracts that. - * - * Returns: a #DBusGProxy capable of calling D-Bus methods of the calling process - */ -DBusGProxy * -nm_dbus_manager_new_proxy (NMDBusManager *self, - DBusGMethodInvocation *context, - const char *name, - const char *path, - const char *iface) -{ - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - DBusGConnection *connection; - GSList *iter; - const char *owner; - - connection = dbus_g_method_invocation_get_g_connection (context); - g_assert (connection); - - /* Might be a private connection, for which we fake a sender */ - for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) { - PrivateServer *s = iter->data; - - owner = private_server_get_connection_owner (s, connection); - if (owner) { - g_assert_cmpstr (owner, ==, name); - return dbus_g_proxy_new_for_peer (connection, path, iface); - } - } - - return dbus_g_proxy_new_for_name (connection, name, path, iface); -} - -#if !HAVE_DBUS_GLIB_GMI_GET_CONNECTION -struct _HACKDBusGMethodInvocation { - DBusGConnection *connection; - /* ... */ -}; - -DBusGConnection * -dbus_g_method_invocation_get_g_connection (DBusGMethodInvocation *context) -{ - /* Evil hack; this method exists in dbus-glib >= 101, but if we don't - * have that, emulate it. - */ - return ((struct _HACKDBusGMethodInvocation *) context)->connection; -} -#endif /* HAVE_DBUS_GLIB_GMI_GET_CONNECTION */ diff --git a/src/nm-dbus-manager.h b/src/nm-dbus-manager.h deleted file mode 100644 index c87ee024..00000000 --- a/src/nm-dbus-manager.h +++ /dev/null @@ -1,133 +0,0 @@ -/* -*- 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) 2006 - 2008 Red Hat, Inc. - * Copyright (C) 2006 - 2008 Novell, Inc. - */ - -#ifndef __NM_DBUS_MANAGER_H__ -#define __NM_DBUS_MANAGER_H__ - -#include -#include -#include -#include - -#include "nm-types.h" - -G_BEGIN_DECLS - -typedef gboolean (* NMDBusSignalHandlerFunc) (DBusConnection * connection, - DBusMessage * message, - gpointer user_data); - -#define NM_TYPE_DBUS_MANAGER (nm_dbus_manager_get_type ()) -#define NM_DBUS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), NM_TYPE_DBUS_MANAGER, NMDBusManager)) -#define NM_DBUS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), NM_TYPE_DBUS_MANAGER, NMDBusManagerClass)) -#define NM_IS_DBUS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), NM_TYPE_DBUS_MANAGER)) -#define NM_IS_DBUS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), NM_TYPE_DBUS_MANAGER)) -#define NM_DBUS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), NM_TYPE_DBUS_MANAGER, NMDBusManagerClass)) - -#define NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED "dbus-connection-changed" -#define NM_DBUS_MANAGER_NAME_OWNER_CHANGED "name-owner-changed" -#define NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW "private-connection-new" -#define NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED "private-connection-disconnected" - -struct _NMDBusManager { - GObject parent; -}; - -typedef struct { - GObjectClass parent; - - /* Signals */ - void (*dbus_connection_changed) (NMDBusManager *mgr, - DBusConnection *connection); - - void (*name_owner_changed) (NMDBusManager *mgr, - const char *name, - const char *old_owner, - const char *new_owner); - - void (*private_connection_new) (NMDBusManager *mgr, - DBusGConnection *connection); - - void (*private_connection_disconnected) (NMDBusManager *mgr, - DBusGConnection *connection); -} NMDBusManagerClass; - -GType nm_dbus_manager_get_type (void); - -NMDBusManager * nm_dbus_manager_get (void); -void nm_dbus_manager_setup (NMDBusManager *instance); - -char * nm_dbus_manager_get_name_owner (NMDBusManager *self, - const char *name, - GError **error); - -gboolean nm_dbus_manager_start_service (NMDBusManager *self); - -gboolean nm_dbus_manager_name_has_owner (NMDBusManager *self, - const char *name); - -DBusConnection * nm_dbus_manager_get_dbus_connection (NMDBusManager *self); -DBusGConnection * nm_dbus_manager_get_connection (NMDBusManager *self); - -gboolean nm_dbus_manager_get_caller_info (NMDBusManager *self, - DBusGMethodInvocation *context, - char **out_sender, - gulong *out_uid, - gulong *out_pid); - -gboolean nm_dbus_manager_get_unix_user (NMDBusManager *self, - const char *sender, - gulong *out_uid); - -gboolean nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self, - DBusConnection *connection, - DBusMessage *message, - char **out_sender, - gulong *out_uid, - gulong *out_pid); - -void nm_dbus_manager_register_exported_type (NMDBusManager *self, - GType object_type, - const DBusGObjectInfo *info); - -void nm_dbus_manager_register_object (NMDBusManager *self, - const char *path, - gpointer object); - -void nm_dbus_manager_unregister_object (NMDBusManager *self, gpointer object); - -void nm_dbus_manager_private_server_register (NMDBusManager *self, - const char *path, - const char *tag); - -DBusGProxy *nm_dbus_manager_new_proxy (NMDBusManager *self, - DBusGMethodInvocation *context, - const char *name, - const char *path, - const char *iface); - -#if !HAVE_DBUS_GLIB_GMI_GET_CONNECTION -DBusGConnection *dbus_g_method_invocation_get_g_connection (DBusGMethodInvocation *context); -#endif - -G_END_DECLS - -#endif /* __NM_DBUS_MANAGER_H__ */ diff --git a/src/nm-dcb.c b/src/nm-dcb.c index 8bf3858a..109e56e5 100644 --- a/src/nm-dcb.c +++ b/src/nm-dcb.c @@ -23,11 +23,10 @@ #include #include -#include +#include "nm-default.h" #include "nm-dcb.h" #include "nm-platform.h" #include "NetworkManagerUtils.h" -#include "nm-logging.h" static const char *helper_names[] = { "dcbtool", "fcoeadm" }; diff --git a/src/nm-dcb.h b/src/nm-dcb.h index e409dd48..86e6153d 100644 --- a/src/nm-dcb.h +++ b/src/nm-dcb.h @@ -21,7 +21,7 @@ #ifndef __NETWORKMANAGER_DCB_H__ #define __NETWORKMANAGER_DCB_H__ -#include +#include "nm-default.h" #include "nm-setting-dcb.h" gboolean nm_dcb_enable (const char *iface, gboolean enable, GError **error); diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c index c5b2e408..a27cb287 100644 --- a/src/nm-default-route-manager.c +++ b/src/nm-default-route-manager.c @@ -23,8 +23,8 @@ #include +#include "nm-default.h" #include "nm-default-route-manager.h" -#include "nm-logging.h" #include "nm-device.h" #include "nm-vpn-connection.h" #include "nm-platform.h" @@ -117,7 +117,7 @@ NM_DEFINE_SINGLETON_GETTER (NMDefaultRouteManager, nm_default_route_manager_get, __entry_idx, \ NM_IS_DEVICE (__entry->source.pointer) ? "dev" : "vpn", \ __entry->source.pointer, \ - NM_IS_DEVICE (__entry->source.pointer) ? nm_device_get_iface (__entry->source.device) : nm_vpn_connection_get_connection_id (__entry->source.vpn), \ + NM_IS_DEVICE (__entry->source.pointer) ? nm_device_get_iface (__entry->source.device) : nm_active_connection_get_settings_connection_id (NM_ACTIVE_CONNECTION (__entry->source.vpn)), \ (__entry->never_default ? '0' : '1'), \ (__entry->synced ? '+' : '-') \ _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ @@ -305,7 +305,7 @@ _platform_route_sync_add (const VTableIP *vtable, NMDefaultRouteManager *self, g } if (!success) { _LOGW (vtable->vt->addr_family, "failed to add default route %s with effective metric %u", - vtable->vt->route_to_string (&entry->route), (guint) entry->effective_metric); + vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) entry->effective_metric); } return TRUE; } @@ -577,23 +577,23 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c g_array_append_val (changed_metrics, expected_metric); if (old_entry) { _LOG2D (vtable, i, entry, "sync:update %s (%u -> %u)", - vtable->vt->route_to_string (&entry->route), (guint) old_entry->effective_metric, + vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) old_entry->effective_metric, (guint) expected_metric); } else { _LOG2D (vtable, i, entry, "sync:add %s (%u)", - vtable->vt->route_to_string (&entry->route), (guint) expected_metric); + vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) expected_metric); } } else if (entry->effective_metric != expected_metric) { g_array_append_val (changed_metrics, entry->effective_metric); g_array_append_val (changed_metrics, expected_metric); _LOG2D (vtable, i, entry, "sync:metric %s (%u -> %u)", - vtable->vt->route_to_string (&entry->route), (guint) entry->effective_metric, + vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) entry->effective_metric, (guint) expected_metric); } else { if (!_vt_routes_has_entry (vtable, routes, entry)) { g_array_append_val (changed_metrics, entry->effective_metric); _LOG2D (vtable, i, entry, "sync:re-add %s (%u -> %u)", - vtable->vt->route_to_string (&entry->route), (guint) entry->effective_metric, + vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) entry->effective_metric, (guint) entry->effective_metric); } } @@ -659,7 +659,7 @@ _entry_at_idx_update (const VTableIP *vtable, NMDefaultRouteManager *self, guint _LOG2D (vtable, entry_idx, entry, "%s %s (%"G_GUINT32_FORMAT")", old_entry ? "record:update" : "record:add ", - vtable->vt->route_to_string (&entry->route), + vtable->vt->route_to_string (&entry->route, NULL, 0), entry->effective_metric); g_ptr_array_sort_with_data (entries, _sort_entries_cmp, NULL); @@ -681,7 +681,7 @@ _entry_at_idx_remove (const VTableIP *vtable, NMDefaultRouteManager *self, guint entry = g_ptr_array_index (entries, entry_idx); _LOG2D (vtable, entry_idx, entry, "record:remove %s (%u)", - vtable->vt->route_to_string (&entry->route), (guint) entry->effective_metric); + vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) entry->effective_metric); /* Remove the entry from the list (but don't free it yet) */ g_ptr_array_index (entries, entry_idx) = NULL; @@ -779,7 +779,7 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self, } else synced = default_route && !is_assumed; } else { - NMConnection *connection = nm_active_connection_get_connection ((NMActiveConnection *) vpn); + NMConnection *connection = nm_active_connection_get_applied_connection ((NMActiveConnection *) vpn); if ( connection && nm_vpn_connection_get_vpn_state (vpn) == NM_VPN_CONNECTION_STATE_ACTIVATED) { @@ -1048,7 +1048,7 @@ _ipx_get_best_activating_device (const VTableIP *vtable, NMDefaultRouteManager * || state >= NM_DEVICE_STATE_DEACTIVATING) continue; - if (!_ipx_connection_has_default_route (vtable, self, nm_device_get_connection (device), NULL)) + if (!_ipx_connection_has_default_route (vtable, self, nm_device_get_applied_connection (device), NULL)) continue; prio = nm_device_get_ip4_route_metric (device); @@ -1359,7 +1359,6 @@ _platform_changed_cb (NMPlatform *platform, int ifindex, gpointer platform_object, NMPlatformSignalChangeType change_type, - NMPlatformReason reason, NMDefaultRouteManager *self) { switch (obj_type) { @@ -1390,7 +1389,7 @@ nm_default_route_manager_init (NMDefaultRouteManager *self) priv->entries_ip4 = g_ptr_array_new_full (0, (GDestroyNotify) _entry_free); priv->entries_ip6 = g_ptr_array_new_full (0, (GDestroyNotify) _entry_free); - priv->platform = g_object_ref (nm_platform_get ()); + priv->platform = g_object_ref (NM_PLATFORM_GET); g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, G_CALLBACK (_platform_changed_cb), self); g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, G_CALLBACK (_platform_changed_cb), self); g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (_platform_changed_cb), self); diff --git a/src/nm-default-route-manager.h b/src/nm-default-route-manager.h index 7fc27bbd..2ee4b6d6 100644 --- a/src/nm-default-route-manager.h +++ b/src/nm-default-route-manager.h @@ -18,10 +18,9 @@ * Copyright (C) 2014 Red Hat, Inc. */ -#include +#include "nm-default.h" #include "nm-connection.h" -#include "nm-types.h" #ifndef __NETWORKMANAGER_DEFAULT_ROUTE_MANAGER_H__ #define __NETWORKMANAGER_DEFAULT_ROUTE_MANAGER_H__ diff --git a/src/nm-device-bond-glue.h b/src/nm-device-bond-glue.h deleted file mode 100644 index 6a2f5702..00000000 --- a/src/nm-device-bond-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_bond_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_bond_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_bond_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_bond_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_bond_object_info = { 1, - dbus_glib_nm_device_bond_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.Bond\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.Bond\0HwAddress\0hw_address\0read\0org.freedesktop.NetworkManager.Device.Bond\0Carrier\0carrier\0read\0org.freedesktop.NetworkManager.Device.Bond\0Slaves\0slaves\0read\0\0" -}; - diff --git a/src/nm-device-bridge-glue.h b/src/nm-device-bridge-glue.h deleted file mode 100644 index 63b86954..00000000 --- a/src/nm-device-bridge-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_bridge_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_bridge_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_bridge_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_bridge_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_bridge_object_info = { 1, - dbus_glib_nm_device_bridge_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.Bridge\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.Bridge\0HwAddress\0hw_address\0read\0org.freedesktop.NetworkManager.Device.Bridge\0Carrier\0carrier\0read\0org.freedesktop.NetworkManager.Device.Bridge\0Slaves\0slaves\0read\0\0" -}; - diff --git a/src/nm-device-ethernet-glue.h b/src/nm-device-ethernet-glue.h deleted file mode 100644 index 81630086..00000000 --- a/src/nm-device-ethernet-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_ethernet_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_ethernet_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_ethernet_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_ethernet_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_ethernet_object_info = { 1, - dbus_glib_nm_device_ethernet_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.Wired\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.Wired\0HwAddress\0hw_address\0read\0org.freedesktop.NetworkManager.Device.Wired\0PermHwAddress\0perm_hw_address\0read\0org.freedesktop.NetworkManager.Device.Wired\0Speed\0speed\0read\0org.freedesktop.NetworkManager.Device.Wired\0Carrier\0carrier\0read\0\0" -}; - diff --git a/src/nm-device-generic-glue.h b/src/nm-device-generic-glue.h deleted file mode 100644 index 472ade14..00000000 --- a/src/nm-device-generic-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_generic_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_generic_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_generic_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_generic_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_generic_object_info = { 1, - dbus_glib_nm_device_generic_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.Generic\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.Generic\0HwAddress\0hw_address\0read\0org.freedesktop.NetworkManager.Device.Generic\0TypeDescription\0type_description\0read\0\0" -}; - diff --git a/src/nm-device-glue.h b/src/nm-device-glue.h deleted file mode 100644 index c511c84c..00000000 --- a/src/nm-device-glue.h +++ /dev/null @@ -1,79 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -/* NONE:POINTER */ -#define dbus_glib_marshal_nm_device_VOID__POINTER g_cclosure_marshal_VOID__POINTER -#define dbus_glib_marshal_nm_device_NONE__POINTER dbus_glib_marshal_nm_device_VOID__POINTER - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_methods[] = { - { (GCallback) impl_device_disconnect, dbus_glib_marshal_nm_device_NONE__POINTER, 0 }, - { (GCallback) impl_device_delete, dbus_glib_marshal_nm_device_NONE__POINTER, 52 }, -}; - -const DBusGObjectInfo dbus_glib_nm_device_object_info = { 1, - dbus_glib_nm_device_methods, - 2, -"org.freedesktop.NetworkManager.Device\0Disconnect\0A\0\0org.freedesktop.NetworkManager.Device\0Delete\0A\0\0\0", -"org.freedesktop.NetworkManager.Device\0StateChanged\0\0", -"org.freedesktop.NetworkManager.Device\0Udi\0udi\0read\0org.freedesktop.NetworkManager.Device\0Interface\0interface\0read\0org.freedesktop.NetworkManager.Device\0IpInterface\0ip_interface\0read\0org.freedesktop.NetworkManager.Device\0Driver\0driver\0read\0org.freedesktop.NetworkManager.Device\0DriverVersion\0driver_version\0read\0org.freedesktop.NetworkManager.Device\0FirmwareVersion\0firmware_version\0read\0org.freedesktop.NetworkManager.Device\0Capabilities\0capabilities\0read\0org.freedesktop.NetworkManager.Device\0Ip4Address\0ip4_address\0read\0org.freedesktop.NetworkManager.Device\0State\0state\0read\0org.freedesktop.NetworkManager.Device\0StateReason\0state_reason\0read\0org.freedesktop.NetworkManager.Device\0ActiveConnection\0active_connection\0read\0org.freedesktop.NetworkManager.Device\0Ip4Config\0ip4_config\0read\0org.freedesktop.NetworkManager.Device\0Dhcp4Config\0dhcp4_config\0read\0org.freedesktop.NetworkManager.Device\0Ip6Config\0ip6_config\0read\0org.freedesktop.NetworkManager.Device\0Dhcp6Config\0dhcp6_config\0read\0org.freedesktop.NetworkManager.Device\0Managed\0managed\0read\0org.freedesktop.NetworkManager.Device\0Autoconnect\0autoconnect\0readwrite\0org.freedesktop.NetworkManager.Device\0FirmwareMissing\0firmware_missing\0read\0org.freedesktop.NetworkManager.Device\0DeviceType\0device_type\0read\0org.freedesktop.NetworkManager.Device\0AvailableConnections\0available_connections\0read\0org.freedesktop.NetworkManager.Device\0PhysicalPortId\0physical_port_id\0read\0org.freedesktop.NetworkManager.Device\0Mtu\0mtu\0read\0org.freedesktop.NetworkManager.Device\0Metered\0metered\0read\0\0" -}; - diff --git a/src/nm-device-gre-glue.h b/src/nm-device-gre-glue.h deleted file mode 100644 index 1347170d..00000000 --- a/src/nm-device-gre-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_gre_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_gre_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_gre_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_gre_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_gre_object_info = { 1, - dbus_glib_nm_device_gre_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.Gre\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.Gre\0Parent\0parent\0read\0org.freedesktop.NetworkManager.Device.Gre\0InputFlags\0input_flags\0read\0org.freedesktop.NetworkManager.Device.Gre\0OutputFlags\0output_flags\0read\0org.freedesktop.NetworkManager.Device.Gre\0InputKey\0input_key\0read\0org.freedesktop.NetworkManager.Device.Gre\0OutputKey\0output_key\0read\0org.freedesktop.NetworkManager.Device.Gre\0Local\0local\0read\0org.freedesktop.NetworkManager.Device.Gre\0Remote\0remote\0read\0org.freedesktop.NetworkManager.Device.Gre\0Ttl\0ttl\0read\0org.freedesktop.NetworkManager.Device.Gre\0Tos\0tos\0read\0org.freedesktop.NetworkManager.Device.Gre\0PathMtuDiscovery\0path_mtu_discovery\0read\0\0" -}; - diff --git a/src/nm-device-infiniband-glue.h b/src/nm-device-infiniband-glue.h deleted file mode 100644 index a762f57c..00000000 --- a/src/nm-device-infiniband-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_infiniband_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_infiniband_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_infiniband_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_infiniband_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_infiniband_object_info = { 1, - dbus_glib_nm_device_infiniband_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.Infiniband\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.Infiniband\0HwAddress\0hw_address\0read\0org.freedesktop.NetworkManager.Device.Infiniband\0Carrier\0carrier\0read\0\0" -}; - diff --git a/src/nm-device-macvlan-glue.h b/src/nm-device-macvlan-glue.h deleted file mode 100644 index 18f5d602..00000000 --- a/src/nm-device-macvlan-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_macvlan_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_macvlan_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_macvlan_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_macvlan_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_macvlan_object_info = { 1, - dbus_glib_nm_device_macvlan_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.Macvlan\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.Macvlan\0Parent\0parent\0read\0org.freedesktop.NetworkManager.Device.Macvlan\0Mode\0mode\0read\0org.freedesktop.NetworkManager.Device.Macvlan\0NoPromisc\0no_promisc\0read\0\0" -}; - diff --git a/src/nm-device-tun-glue.h b/src/nm-device-tun-glue.h deleted file mode 100644 index 96cea85b..00000000 --- a/src/nm-device-tun-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_tun_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_tun_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_tun_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_tun_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_tun_object_info = { 1, - dbus_glib_nm_device_tun_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.Tun\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.Tun\0Owner\0owner\0read\0org.freedesktop.NetworkManager.Device.Tun\0Group\0group\0read\0org.freedesktop.NetworkManager.Device.Tun\0Mode\0mode\0read\0org.freedesktop.NetworkManager.Device.Tun\0NoPi\0no_pi\0read\0org.freedesktop.NetworkManager.Device.Tun\0VnetHdr\0vnet_hdr\0read\0org.freedesktop.NetworkManager.Device.Tun\0MultiQueue\0multi_queue\0read\0\0" -}; - diff --git a/src/nm-device-veth-glue.h b/src/nm-device-veth-glue.h deleted file mode 100644 index f411964e..00000000 --- a/src/nm-device-veth-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_veth_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_veth_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_veth_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_veth_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_veth_object_info = { 1, - dbus_glib_nm_device_veth_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.Veth\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.Veth\0Peer\0peer\0read\0\0" -}; - diff --git a/src/nm-device-vlan-glue.h b/src/nm-device-vlan-glue.h deleted file mode 100644 index cd1f5580..00000000 --- a/src/nm-device-vlan-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_vlan_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_vlan_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_vlan_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_vlan_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_vlan_object_info = { 1, - dbus_glib_nm_device_vlan_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.Vlan\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.Vlan\0HwAddress\0hw_address\0read\0org.freedesktop.NetworkManager.Device.Vlan\0Carrier\0carrier\0read\0org.freedesktop.NetworkManager.Device.Vlan\0Parent\0parent\0read\0org.freedesktop.NetworkManager.Device.Vlan\0VlanId\0vlan_id\0read\0\0" -}; - diff --git a/src/nm-device-vxlan-glue.h b/src/nm-device-vxlan-glue.h deleted file mode 100644 index 988dbd32..00000000 --- a/src/nm-device-vxlan-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_device_vxlan_MARSHAL_H__ -#define __dbus_glib_marshal_nm_device_vxlan_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_device_vxlan_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_device_vxlan_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_device_vxlan_object_info = { 1, - dbus_glib_nm_device_vxlan_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.Device.Vxlan\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Device.Vxlan\0Parent\0parent\0read\0org.freedesktop.NetworkManager.Device.Vxlan\0Id\0id\0read\0org.freedesktop.NetworkManager.Device.Vxlan\0Group\0group\0read\0org.freedesktop.NetworkManager.Device.Vxlan\0Local\0local\0read\0org.freedesktop.NetworkManager.Device.Vxlan\0Tos\0tos\0read\0org.freedesktop.NetworkManager.Device.Vxlan\0Ttl\0ttl\0read\0org.freedesktop.NetworkManager.Device.Vxlan\0Learning\0learning\0read\0org.freedesktop.NetworkManager.Device.Vxlan\0Ageing\0ageing\0read\0org.freedesktop.NetworkManager.Device.Vxlan\0Limit\0limit\0read\0org.freedesktop.NetworkManager.Device.Vxlan\0DstPort\0dst_port\0read\0org.freedesktop.NetworkManager.Device.Vxlan\0SrcPortMin\0src_port_min\0read\0org.freedesktop.NetworkManager.Device.Vxlan\0SrcPortMax\0src_port_max\0read\0org.freedesktop.NetworkManager.Device.Vxlan\0Proxy\0proxy\0read\0org.freedesktop.NetworkManager.Device.Vxlan\0Rsc\0rsc\0read\0org.freedesktop.NetworkManager.Device.Vxlan\0L2miss\0l2miss\0read\0org.freedesktop.NetworkManager.Device.Vxlan\0L3miss\0l3miss\0read\0\0" -}; - diff --git a/src/nm-dhcp4-config-glue.h b/src/nm-dhcp4-config-glue.h deleted file mode 100644 index b08a611b..00000000 --- a/src/nm-dhcp4-config-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_dhcp4_config_MARSHAL_H__ -#define __dbus_glib_marshal_nm_dhcp4_config_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_dhcp4_config_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_dhcp4_config_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_dhcp4_config_object_info = { 1, - dbus_glib_nm_dhcp4_config_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.DHCP4Config\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.DHCP4Config\0Options\0options\0read\0\0" -}; - diff --git a/src/nm-dhcp4-config.c b/src/nm-dhcp4-config.c index 096cf16d..00b9949b 100644 --- a/src/nm-dhcp4-config.c +++ b/src/nm-dhcp4-config.c @@ -20,24 +20,21 @@ #include "config.h" -#include #include +#include "nm-default.h" #include "nm-dbus-interface.h" -#include "nm-dbus-manager.h" #include "nm-dhcp4-config.h" -#include "nm-dhcp4-config-glue.h" -#include "nm-dbus-glib-types.h" #include "nm-utils.h" +#include "nmdbus-dhcp4-config.h" -G_DEFINE_TYPE (NMDhcp4Config, nm_dhcp4_config, G_TYPE_OBJECT) +G_DEFINE_TYPE (NMDhcp4Config, nm_dhcp4_config, NM_TYPE_EXPORTED_OBJECT) #define NM_DHCP4_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP4_CONFIG, NMDhcp4ConfigPrivate)) typedef struct { - char *dbus_path; - GHashTable *options; + GVariant *options; } NMDhcp4ConfigPrivate; @@ -56,88 +53,59 @@ nm_dhcp4_config_new (void) } void -nm_dhcp4_config_add_option (NMDhcp4Config *self, - const char *key, - const char *option) +nm_dhcp4_config_set_options (NMDhcp4Config *self, + GHashTable *options) { - GValue *svalue; + NMDhcp4ConfigPrivate *priv = NM_DHCP4_CONFIG_GET_PRIVATE (self); + GHashTableIter iter; + const char *key, *value; + GVariantBuilder builder; g_return_if_fail (NM_IS_DHCP4_CONFIG (self)); - g_return_if_fail (key != NULL); - g_return_if_fail (option != NULL); + g_return_if_fail (options != NULL); - svalue = g_slice_new0 (GValue); - g_value_init (svalue, G_TYPE_STRING); - g_value_set_string (svalue, option); - g_hash_table_insert (NM_DHCP4_CONFIG_GET_PRIVATE (self)->options, g_strdup (key), svalue); - g_object_notify (G_OBJECT (self), NM_DHCP4_CONFIG_OPTIONS); -} + g_variant_unref (priv->options); -void -nm_dhcp4_config_reset (NMDhcp4Config *self) -{ - g_return_if_fail (NM_IS_DHCP4_CONFIG (self)); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + g_hash_table_iter_init (&iter, options); + while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value)) + g_variant_builder_add (&builder, "{sv}", key, g_variant_new_string (value)); - g_hash_table_remove_all (NM_DHCP4_CONFIG_GET_PRIVATE (self)->options); + priv->options = g_variant_builder_end (&builder); + g_variant_ref_sink (priv->options); g_object_notify (G_OBJECT (self), NM_DHCP4_CONFIG_OPTIONS); } const char * nm_dhcp4_config_get_option (NMDhcp4Config *self, const char *key) { - GValue *value; + NMDhcp4ConfigPrivate *priv = NM_DHCP4_CONFIG_GET_PRIVATE (self); + const char *value; g_return_val_if_fail (NM_IS_DHCP4_CONFIG (self), NULL); g_return_val_if_fail (key != NULL, NULL); - value = g_hash_table_lookup (NM_DHCP4_CONFIG_GET_PRIVATE (self)->options, key); - return value ? g_value_get_string (value) : NULL; -} - -/* Caller owns the list, but not the values in the list */ -GSList * -nm_dhcp4_config_list_options (NMDhcp4Config *self) -{ - GHashTableIter iter; - const char *option = NULL; - GSList *list = NULL; - - g_return_val_if_fail (NM_IS_DHCP4_CONFIG (self), NULL); - - g_hash_table_iter_init (&iter, NM_DHCP4_CONFIG_GET_PRIVATE (self)->options); - while (g_hash_table_iter_next (&iter, (gpointer) &option, NULL)) - list = g_slist_prepend (list, (gpointer) option); - - return list; + if (g_variant_lookup (priv->options, key, "&s", &value)) + return value; + else + return NULL; } -const char * -nm_dhcp4_config_get_dbus_path (NMDhcp4Config *self) +GVariant * +nm_dhcp4_config_get_options (NMDhcp4Config *self) { g_return_val_if_fail (NM_IS_DHCP4_CONFIG (self), NULL); - return NM_DHCP4_CONFIG_GET_PRIVATE (self)->dbus_path; -} - -static void -nm_gvalue_destroy (gpointer data) -{ - GValue *value = (GValue *) data; - - g_value_unset (value); - g_slice_free (GValue, value); + return g_variant_ref (NM_DHCP4_CONFIG_GET_PRIVATE (self)->options); } static void nm_dhcp4_config_init (NMDhcp4Config *self) { NMDhcp4ConfigPrivate *priv = NM_DHCP4_CONFIG_GET_PRIVATE (self); - static guint32 counter = 0; - - priv->dbus_path = g_strdup_printf (NM_DBUS_PATH "/DHCP4Config/%d", counter++); - nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->dbus_path, self); - priv->options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, nm_gvalue_destroy); + priv->options = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0); + g_variant_ref_sink (priv->options); } static void @@ -145,8 +113,7 @@ finalize (GObject *object) { NMDhcp4ConfigPrivate *priv = NM_DHCP4_CONFIG_GET_PRIVATE (object); - g_free (priv->dbus_path); - g_hash_table_destroy (priv->options); + g_variant_unref (priv->options); G_OBJECT_CLASS (nm_dhcp4_config_parent_class)->finalize (object); } @@ -159,7 +126,7 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_OPTIONS: - g_value_set_boxed (value, priv->options); + g_value_set_variant (value, priv->options); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -171,9 +138,13 @@ static void nm_dhcp4_config_class_init (NMDhcp4ConfigClass *config_class) { GObjectClass *object_class = G_OBJECT_CLASS (config_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (config_class); g_type_class_add_private (config_class, sizeof (NMDhcp4ConfigPrivate)); + exported_object_class->export_path = NM_DBUS_PATH "/DHCP4Config/%u"; + exported_object_class->export_on_construction = TRUE; + /* virtual methods */ object_class->get_property = get_property; object_class->finalize = finalize; @@ -181,12 +152,13 @@ nm_dhcp4_config_class_init (NMDhcp4ConfigClass *config_class) /* properties */ g_object_class_install_property (object_class, PROP_OPTIONS, - g_param_spec_boxed (NM_DHCP4_CONFIG_OPTIONS, "", "", - DBUS_TYPE_G_MAP_OF_VARIANT, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (config_class), - &dbus_glib_nm_dhcp4_config_object_info); + g_param_spec_variant (NM_DHCP4_CONFIG_OPTIONS, "", "", + G_VARIANT_TYPE ("a{sv}"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (config_class), + NMDBUS_TYPE_DHCP4_CONFIG_SKELETON, + NULL); } diff --git a/src/nm-dhcp4-config.h b/src/nm-dhcp4-config.h index 227d4481..080e28de 100644 --- a/src/nm-dhcp4-config.h +++ b/src/nm-dhcp4-config.h @@ -21,10 +21,7 @@ #ifndef __NETWORKMANAGER_DHCP4_CONFIG_H__ #define __NETWORKMANAGER_DHCP4_CONFIG_H__ -#include -#include - -#include "nm-types.h" +#include "nm-exported-object.h" #define NM_TYPE_DHCP4_CONFIG (nm_dhcp4_config_get_type ()) #define NM_DHCP4_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP4_CONFIG, NMDhcp4Config)) @@ -34,11 +31,11 @@ #define NM_DHCP4_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP4_CONFIG, NMDhcp4ConfigClass)) struct _NMDhcp4Config { - GObject parent; + NMExportedObject parent; }; typedef struct { - GObjectClass parent; + NMExportedObjectClass parent; } NMDhcp4ConfigClass; @@ -48,16 +45,11 @@ GType nm_dhcp4_config_get_type (void); NMDhcp4Config *nm_dhcp4_config_new (void); -const char *nm_dhcp4_config_get_dbus_path (NMDhcp4Config *config); - -void nm_dhcp4_config_add_option (NMDhcp4Config *config, - const char *key, - const char *option); - -void nm_dhcp4_config_reset (NMDhcp4Config *config); +void nm_dhcp4_config_set_options (NMDhcp4Config *config, + GHashTable *options); const char *nm_dhcp4_config_get_option (NMDhcp4Config *config, const char *option); -GSList *nm_dhcp4_config_list_options (NMDhcp4Config *config); +GVariant *nm_dhcp4_config_get_options (NMDhcp4Config *config); #endif /* __NETWORKMANAGER_DHCP4_CONFIG_H__ */ diff --git a/src/nm-dhcp6-config-glue.h b/src/nm-dhcp6-config-glue.h deleted file mode 100644 index 9bfee43d..00000000 --- a/src/nm-dhcp6-config-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_dhcp6_config_MARSHAL_H__ -#define __dbus_glib_marshal_nm_dhcp6_config_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_dhcp6_config_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_dhcp6_config_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_dhcp6_config_object_info = { 1, - dbus_glib_nm_dhcp6_config_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.DHCP6Config\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.DHCP6Config\0Options\0options\0read\0\0" -}; - diff --git a/src/nm-dhcp6-config.c b/src/nm-dhcp6-config.c index f93e9644..8aa8c2e0 100644 --- a/src/nm-dhcp6-config.c +++ b/src/nm-dhcp6-config.c @@ -20,24 +20,21 @@ #include "config.h" -#include #include +#include "nm-default.h" #include "nm-dbus-interface.h" -#include "nm-dbus-manager.h" #include "nm-dhcp6-config.h" -#include "nm-dhcp6-config-glue.h" -#include "nm-dbus-glib-types.h" #include "nm-utils.h" +#include "nmdbus-dhcp6-config.h" -G_DEFINE_TYPE (NMDhcp6Config, nm_dhcp6_config, G_TYPE_OBJECT) +G_DEFINE_TYPE (NMDhcp6Config, nm_dhcp6_config, NM_TYPE_EXPORTED_OBJECT) #define NM_DHCP6_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DHCP6_CONFIG, NMDhcp6ConfigPrivate)) typedef struct { - char *dbus_path; - GHashTable *options; + GVariant *options; } NMDhcp6ConfigPrivate; @@ -56,88 +53,59 @@ nm_dhcp6_config_new (void) } void -nm_dhcp6_config_add_option (NMDhcp6Config *self, - const char *key, - const char *option) +nm_dhcp6_config_set_options (NMDhcp6Config *self, + GHashTable *options) { - GValue *svalue; + NMDhcp6ConfigPrivate *priv = NM_DHCP6_CONFIG_GET_PRIVATE (self); + GHashTableIter iter; + const char *key, *value; + GVariantBuilder builder; g_return_if_fail (NM_IS_DHCP6_CONFIG (self)); - g_return_if_fail (key != NULL); - g_return_if_fail (option != NULL); + g_return_if_fail (options != NULL); - svalue = g_slice_new0 (GValue); - g_value_init (svalue, G_TYPE_STRING); - g_value_set_string (svalue, option); - g_hash_table_insert (NM_DHCP6_CONFIG_GET_PRIVATE (self)->options, g_strdup (key), svalue); - g_object_notify (G_OBJECT (self), NM_DHCP6_CONFIG_OPTIONS); -} + g_variant_unref (priv->options); -void -nm_dhcp6_config_reset (NMDhcp6Config *self) -{ - g_return_if_fail (NM_IS_DHCP6_CONFIG (self)); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + g_hash_table_iter_init (&iter, options); + while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &value)) + g_variant_builder_add (&builder, "{sv}", key, g_variant_new_string (value)); - g_hash_table_remove_all (NM_DHCP6_CONFIG_GET_PRIVATE (self)->options); + priv->options = g_variant_builder_end (&builder); + g_variant_ref_sink (priv->options); g_object_notify (G_OBJECT (self), NM_DHCP6_CONFIG_OPTIONS); } const char * nm_dhcp6_config_get_option (NMDhcp6Config *self, const char *key) { - GValue *value; + NMDhcp6ConfigPrivate *priv = NM_DHCP6_CONFIG_GET_PRIVATE (self); + const char *value; g_return_val_if_fail (NM_IS_DHCP6_CONFIG (self), NULL); g_return_val_if_fail (key != NULL, NULL); - value = g_hash_table_lookup (NM_DHCP6_CONFIG_GET_PRIVATE (self)->options, key); - return value ? g_value_get_string (value) : NULL; -} - -/* Caller owns the list, but not the values in the list */ -GSList * -nm_dhcp6_config_list_options (NMDhcp6Config *self) -{ - GHashTableIter iter; - const char *option = NULL; - GSList *list = NULL; - - g_return_val_if_fail (NM_IS_DHCP6_CONFIG (self), NULL); - - g_hash_table_iter_init (&iter, NM_DHCP6_CONFIG_GET_PRIVATE (self)->options); - while (g_hash_table_iter_next (&iter, (gpointer) &option, NULL)) - list = g_slist_prepend (list, (gpointer) option); - - return list; + if (g_variant_lookup (priv->options, key, "&s", &value)) + return value; + else + return NULL; } -const char * -nm_dhcp6_config_get_dbus_path (NMDhcp6Config *self) +GVariant * +nm_dhcp6_config_get_options (NMDhcp6Config *self) { g_return_val_if_fail (NM_IS_DHCP6_CONFIG (self), NULL); - return NM_DHCP6_CONFIG_GET_PRIVATE (self)->dbus_path; -} - -static void -nm_gvalue_destroy (gpointer data) -{ - GValue *value = (GValue *) data; - - g_value_unset (value); - g_slice_free (GValue, value); + return g_variant_ref (NM_DHCP6_CONFIG_GET_PRIVATE (self)->options); } static void nm_dhcp6_config_init (NMDhcp6Config *self) { NMDhcp6ConfigPrivate *priv = NM_DHCP6_CONFIG_GET_PRIVATE (self); - static guint32 counter = 0; - - priv->dbus_path = g_strdup_printf (NM_DBUS_PATH "/DHCP6Config/%d", counter++); - nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->dbus_path, self); - priv->options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, nm_gvalue_destroy); + priv->options = g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0); + g_variant_ref_sink (priv->options); } static void @@ -145,8 +113,7 @@ finalize (GObject *object) { NMDhcp6ConfigPrivate *priv = NM_DHCP6_CONFIG_GET_PRIVATE (object); - g_free (priv->dbus_path); - g_hash_table_destroy (priv->options); + g_variant_unref (priv->options); G_OBJECT_CLASS (nm_dhcp6_config_parent_class)->finalize (object); } @@ -159,7 +126,7 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_OPTIONS: - g_value_set_boxed (value, priv->options); + g_value_set_variant (value, priv->options); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -171,9 +138,13 @@ static void nm_dhcp6_config_class_init (NMDhcp6ConfigClass *config_class) { GObjectClass *object_class = G_OBJECT_CLASS (config_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (config_class); g_type_class_add_private (config_class, sizeof (NMDhcp6ConfigPrivate)); + exported_object_class->export_path = NM_DBUS_PATH "/DHCP6Config/%u"; + exported_object_class->export_on_construction = TRUE; + /* virtual methods */ object_class->get_property = get_property; object_class->finalize = finalize; @@ -181,12 +152,13 @@ nm_dhcp6_config_class_init (NMDhcp6ConfigClass *config_class) /* properties */ g_object_class_install_property (object_class, PROP_OPTIONS, - g_param_spec_boxed (NM_DHCP6_CONFIG_OPTIONS, "", "", - DBUS_TYPE_G_MAP_OF_VARIANT, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (config_class), - &dbus_glib_nm_dhcp6_config_object_info); + g_param_spec_variant (NM_DHCP6_CONFIG_OPTIONS, "", "", + G_VARIANT_TYPE ("a{sv}"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (config_class), + NMDBUS_TYPE_DHCP6_CONFIG_SKELETON, + NULL); } diff --git a/src/nm-dhcp6-config.h b/src/nm-dhcp6-config.h index eaca61b1..c018d97f 100644 --- a/src/nm-dhcp6-config.h +++ b/src/nm-dhcp6-config.h @@ -21,10 +21,7 @@ #ifndef __NETWORKMANAGER_DHCP6_CONFIG_H__ #define __NETWORKMANAGER_DHCP6_CONFIG_H__ -#include -#include - -#include "nm-types.h" +#include "nm-exported-object.h" #define NM_TYPE_DHCP6_CONFIG (nm_dhcp6_config_get_type ()) #define NM_DHCP6_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DHCP6_CONFIG, NMDhcp6Config)) @@ -34,11 +31,11 @@ #define NM_DHCP6_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DHCP6_CONFIG, NMDhcp6ConfigClass)) struct _NMDhcp6Config { - GObject parent; + NMExportedObject parent; }; typedef struct { - GObjectClass parent; + NMExportedObjectClass parent; } NMDhcp6ConfigClass; @@ -48,16 +45,11 @@ GType nm_dhcp6_config_get_type (void); NMDhcp6Config *nm_dhcp6_config_new (void); -const char *nm_dhcp6_config_get_dbus_path (NMDhcp6Config *config); - -void nm_dhcp6_config_add_option (NMDhcp6Config *config, - const char *key, - const char *option); - -void nm_dhcp6_config_reset (NMDhcp6Config *config); +void nm_dhcp6_config_set_options (NMDhcp6Config *config, + GHashTable *options); const char *nm_dhcp6_config_get_option (NMDhcp6Config *config, const char *option); -GSList *nm_dhcp6_config_list_options (NMDhcp6Config *self); +GVariant *nm_dhcp6_config_get_options (NMDhcp6Config *self); #endif /* __NETWORKMANAGER_DHCP6_CONFIG_H__ */ diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c index 78aa204e..dad48520 100644 --- a/src/nm-dispatcher.c +++ b/src/nm-dispatcher.c @@ -21,26 +21,26 @@ #include "config.h" -#include -#include #include #include +#include "nm-default.h" #include "nm-dispatcher.h" #include "nm-dispatcher-api.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" -#include "nm-logging.h" -#include "nm-dbus-manager.h" #include "nm-device.h" #include "nm-dhcp4-config.h" #include "nm-dhcp6-config.h" -#include "nm-dbus-glib-types.h" -#include "nm-glib-compat.h" +#include "nm-ip4-config.h" +#include "nm-ip6-config.h" #include "nm-settings-connection.h" +#include "nm-platform.h" +#include "nm-core-internal.h" #define CALL_TIMEOUT (1000 * 60 * 10) /* 10 minutes for all scripts */ +static GDBusProxy *dispatcher_proxy; static GHashTable *requests = NULL; typedef struct { @@ -80,61 +80,150 @@ _get_monitor_by_action (DispatcherAction action) } static void -dump_object_to_props (GObject *object, GHashTable *hash) +dump_ip4_to_props (NMIP4Config *ip4, GVariantBuilder *builder) { - GParamSpec **pspecs; - guint len = 0, i; - - pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), &len); - for (i = 0; i < len; i++) { - value_hash_add_object_property (hash, - pspecs[i]->name, - object, - pspecs[i]->name, - pspecs[i]->value_type); + GVariantBuilder int_builder; + guint n, i; + const NMPlatformIP4Address *addr; + const NMPlatformIP4Route *route; + guint32 array[4]; + + /* Addresses */ + g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("aau")); + n = nm_ip4_config_get_num_addresses (ip4); + for (i = 0; i < n; i++) { + addr = nm_ip4_config_get_address (ip4, i); + array[0] = addr->address; + array[1] = addr->plen; + array[2] = (i == 0) ? nm_ip4_config_get_gateway (ip4) : 0; + g_variant_builder_add (&int_builder, "@au", + g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, + array, 3, sizeof (guint32))); } - g_free (pspecs); -} - -static void -dump_dhcp4_to_props (NMDhcp4Config *config, GHashTable *hash) -{ - GSList *options, *iter; - - options = nm_dhcp4_config_list_options (config); - for (iter = options; iter; iter = g_slist_next (iter)) { - const char *option = (const char *) iter->data; - const char *val; - - val = nm_dhcp4_config_get_option (config, option); - value_hash_add_str (hash, option, val); + g_variant_builder_add (builder, "{sv}", + "addresses", + g_variant_builder_end (&int_builder)); + + /* DNS servers */ + g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("au")); + n = nm_ip4_config_get_num_nameservers (ip4); + for (i = 0; i < n; i++) + g_variant_builder_add (&int_builder, "u", nm_ip4_config_get_nameserver (ip4, i)); + g_variant_builder_add (builder, "{sv}", + "nameservers", + g_variant_builder_end (&int_builder)); + + /* Search domains */ + g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("as")); + n = nm_ip4_config_get_num_domains (ip4); + for (i = 0; i < n; i++) + g_variant_builder_add (&int_builder, "s", nm_ip4_config_get_domain (ip4, i)); + g_variant_builder_add (builder, "{sv}", + "domains", + g_variant_builder_end (&int_builder)); + + /* WINS servers */ + g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("au")); + n = nm_ip4_config_get_num_wins (ip4); + for (i = 0; i < n; i++) + g_variant_builder_add (&int_builder, "u", nm_ip4_config_get_wins (ip4, i)); + g_variant_builder_add (builder, "{sv}", + "wins-servers", + g_variant_builder_end (&int_builder)); + + /* Static routes */ + g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("aau")); + n = nm_ip4_config_get_num_routes (ip4); + for (i = 0; i < n; i++) { + route = nm_ip4_config_get_route (ip4, i); + array[0] = route->network; + array[1] = route->plen; + array[2] = route->gateway; + array[3] = route->metric; + g_variant_builder_add (&int_builder, "@au", + g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, + array, 4, sizeof (guint32))); } - g_slist_free (options); + g_variant_builder_add (builder, "{sv}", + "routes", + g_variant_builder_end (&int_builder)); } static void -dump_dhcp6_to_props (NMDhcp6Config *config, GHashTable *hash) +dump_ip6_to_props (NMIP6Config *ip6, GVariantBuilder *builder) { - GSList *options, *iter; - - options = nm_dhcp6_config_list_options (config); - for (iter = options; iter; iter = g_slist_next (iter)) { - const char *option = (const char *) iter->data; - const char *val; - - val = nm_dhcp6_config_get_option (config, option); - value_hash_add_str (hash, option, val); + GVariantBuilder int_builder; + guint n, i; + const NMPlatformIP6Address *addr; + const struct in6_addr *gw_bytes; + const NMPlatformIP6Route *route; + GVariant *ip, *gw; + + /* Addresses */ + g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("a(ayuay)")); + n = nm_ip6_config_get_num_addresses (ip6); + for (i = 0; i < n; i++) { + addr = nm_ip6_config_get_address (ip6, i); + gw_bytes = nm_ip6_config_get_gateway (ip6); + ip = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + &addr->address, + sizeof (struct in6_addr), 1); + gw = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + (i == 0 && gw_bytes) ? gw_bytes : &in6addr_any, + sizeof (struct in6_addr), 1); + g_variant_builder_add (&int_builder, "(@ayu@ay)", ip, addr->plen, gw); + } + g_variant_builder_add (builder, "{sv}", + "addresses", + g_variant_builder_end (&int_builder)); + + /* DNS servers */ + g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("aay")); + n = nm_ip6_config_get_num_nameservers (ip6); + for (i = 0; i < n; i++) { + ip = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + nm_ip6_config_get_nameserver (ip6, i), + sizeof (struct in6_addr), 1); + g_variant_builder_add (&int_builder, "@ay", ip); } - g_slist_free (options); + g_variant_builder_add (builder, "{sv}", + "nameservers", + g_variant_builder_end (&int_builder)); + + /* Search domains */ + g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("as")); + n = nm_ip6_config_get_num_domains (ip6); + for (i = 0; i < n; i++) + g_variant_builder_add (&int_builder, "s", nm_ip6_config_get_domain (ip6, i)); + g_variant_builder_add (builder, "{sv}", + "domains", + g_variant_builder_end (&int_builder)); + + /* Static routes */ + g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("a(ayuayu)")); + n = nm_ip6_config_get_num_routes (ip6); + for (i = 0; i < n; i++) { + route = nm_ip6_config_get_route (ip6, i); + ip = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + &route->network, + sizeof (struct in6_addr), 1); + gw = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + &route->gateway, + sizeof (struct in6_addr), 1); + g_variant_builder_add (&int_builder, "(@ayu@ayu)", ip, route->plen, gw, route->metric); + } + g_variant_builder_add (builder, "{sv}", + "routes", + g_variant_builder_end (&int_builder)); } static void fill_device_props (NMDevice *device, - GHashTable *dev_hash, - GHashTable *ip4_hash, - GHashTable *ip6_hash, - GHashTable *dhcp4_hash, - GHashTable *dhcp6_hash) + GVariantBuilder *dev_builder, + GVariantBuilder *ip4_builder, + GVariantBuilder *ip6_builder, + GVariant **dhcp4_props, + GVariant **dhcp6_props) { NMIP4Config *ip4_config; NMIP6Config *ip6_config; @@ -142,39 +231,45 @@ fill_device_props (NMDevice *device, NMDhcp6Config *dhcp6_config; /* If the action is for a VPN, send the VPN's IP interface instead of the device's */ - value_hash_add_str (dev_hash, NMD_DEVICE_PROPS_IP_INTERFACE, nm_device_get_ip_iface (device)); - value_hash_add_str (dev_hash, NMD_DEVICE_PROPS_INTERFACE, nm_device_get_iface (device)); - value_hash_add_uint (dev_hash, NMD_DEVICE_PROPS_TYPE, nm_device_get_device_type (device)); - value_hash_add_uint (dev_hash, NMD_DEVICE_PROPS_STATE, nm_device_get_state (device)); - value_hash_add_object_path (dev_hash, NMD_DEVICE_PROPS_PATH, nm_device_get_path (device)); + g_variant_builder_add (dev_builder, "{sv}", NMD_DEVICE_PROPS_IP_INTERFACE, + g_variant_new_string (nm_device_get_ip_iface (device))); + g_variant_builder_add (dev_builder, "{sv}", NMD_DEVICE_PROPS_INTERFACE, + g_variant_new_string (nm_device_get_iface (device))); + g_variant_builder_add (dev_builder, "{sv}", NMD_DEVICE_PROPS_TYPE, + g_variant_new_uint32 (nm_device_get_device_type (device))); + g_variant_builder_add (dev_builder, "{sv}", NMD_DEVICE_PROPS_STATE, + g_variant_new_uint32 (nm_device_get_state (device))); + if (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (device))) + g_variant_builder_add (dev_builder, "{sv}", NMD_DEVICE_PROPS_PATH, + g_variant_new_object_path (nm_exported_object_get_path (NM_EXPORTED_OBJECT (device)))); ip4_config = nm_device_get_ip4_config (device); if (ip4_config) - dump_object_to_props (G_OBJECT (ip4_config), ip4_hash); + dump_ip4_to_props (ip4_config, ip4_builder); ip6_config = nm_device_get_ip6_config (device); if (ip6_config) - dump_object_to_props (G_OBJECT (ip6_config), ip6_hash); + dump_ip6_to_props (ip6_config, ip6_builder); dhcp4_config = nm_device_get_dhcp4_config (device); if (dhcp4_config) - dump_dhcp4_to_props (dhcp4_config, dhcp4_hash); + *dhcp4_props = nm_dhcp4_config_get_options (dhcp4_config); dhcp6_config = nm_device_get_dhcp6_config (device); if (dhcp6_config) - dump_dhcp6_to_props (dhcp6_config, dhcp6_hash); + *dhcp6_props = nm_dhcp6_config_get_options (dhcp6_config); } static void fill_vpn_props (NMIP4Config *ip4_config, NMIP6Config *ip6_config, - GHashTable *ip4_hash, - GHashTable *ip6_hash) + GVariantBuilder *ip4_builder, + GVariantBuilder *ip6_builder) { if (ip4_config) - dump_object_to_props (G_OBJECT (ip4_config), ip4_hash); + dump_ip4_to_props (ip4_config, ip4_builder); if (ip6_config) - dump_object_to_props (G_OBJECT (ip6_config), ip6_hash); + dump_ip6_to_props (ip6_config, ip6_builder); } typedef struct { @@ -228,51 +323,25 @@ dispatch_result_to_string (DispatchResult result) g_assert_not_reached (); } -static gboolean -validate_element (guint request_id, GValue *val, GType expected_type, guint idx, guint eltnum) -{ - if (G_VALUE_TYPE (val) != expected_type) { - nm_log_dbg (LOGD_DISPATCH, "(%u) result %d element %d invalid type %s", - request_id, idx, eltnum, G_VALUE_TYPE_NAME (val)); - return FALSE; - } - return TRUE; -} - static void -dispatcher_results_process (guint request_id, DispatcherAction action, GPtrArray *results) +dispatcher_results_process (guint request_id, DispatcherAction action, GVariantIter *results) { - guint i; + const char *script, *err; + guint32 result; const Monitor *monitor = _get_monitor_by_action (action); g_return_if_fail (results != NULL); - if (results->len == 0) { + if (g_variant_iter_n_children (results) == 0) { nm_log_dbg (LOGD_DISPATCH, "(%u) succeeded but no scripts invoked", request_id); return; } - for (i = 0; i < results->len; i++) { - GValueArray *item = g_ptr_array_index (results, i); - GValue *tmp; - const char *script, *err; - DispatchResult result; + while (g_variant_iter_next (results, "(&su&s)", &script, &result, &err)) { const char *script_validation_msg = ""; - if (item->n_values != 3) { - nm_log_dbg (LOGD_DISPATCH, "(%u) unexpected number of items in " - "dispatcher result (got %d, expected 3)", - request_id, item->n_values); - continue; - } - - /* Script */ - tmp = g_value_array_get_nth (item, 0); - if (!validate_element (request_id, tmp, G_TYPE_STRING, i, 0)) - continue; - script = g_value_get_string (tmp); - if (!script) { + if (!*script) { script_validation_msg = " (path is NULL)"; script = "(unknown)"; } else if (!strncmp (script, monitor->dir, monitor->dir_len) /* check: prefixed by script directory */ @@ -284,20 +353,6 @@ dispatcher_results_process (guint request_id, DispatcherAction action, GPtrArray } else script_validation_msg = " (unexpected path)"; - - /* Result */ - tmp = g_value_array_get_nth (item, 1); - if (!validate_element (request_id, tmp, G_TYPE_UINT, i, 1)) - continue; - result = g_value_get_uint (tmp); - - /* Error */ - tmp = g_value_array_get_nth (item, 2); - if (!validate_element (request_id, tmp, G_TYPE_STRING, i, 2)) - continue; - err = g_value_get_string (tmp); - - if (result == DISPATCH_RESULT_SUCCESS) { nm_log_dbg (LOGD_DISPATCH, "(%u) %s succeeded%s", request_id, @@ -307,52 +362,43 @@ dispatcher_results_process (guint request_id, DispatcherAction action, GPtrArray request_id, script, dispatch_result_to_string (result), - err ? err : "", script_validation_msg); + err, script_validation_msg); } } } static void -free_results (GPtrArray *results) -{ - g_return_if_fail (results != NULL); - g_ptr_array_foreach (results, (GFunc) g_value_array_free, NULL); - g_ptr_array_free (results, TRUE); -} - -static void -dispatcher_done_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data) +dispatcher_done_cb (GObject *proxy, GAsyncResult *result, gpointer user_data) { DispatchInfo *info = user_data; + GVariant *ret; + GVariantIter *results; GError *error = NULL; - GPtrArray *results = NULL; - if (dbus_g_proxy_end_call (proxy, call, &error, - DISPATCHER_TYPE_RESULT_ARRAY, &results, - G_TYPE_INVALID)) { + ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result, + G_VARIANT_TYPE ("(a(sus))"), + &error); + if (ret) { + g_variant_get (ret, "(a(sus))", &results); dispatcher_results_process (info->request_id, info->action, results); - free_results (results); + g_variant_iter_free (results); + g_variant_unref (ret); } else { - g_assert (error); - - if (!g_error_matches (error, DBUS_GERROR, DBUS_GERROR_REMOTE_EXCEPTION)) { - nm_log_warn (LOGD_DISPATCH, "(%u) failed to call dispatcher scripts: (%s:%d) %s", - info->request_id, g_quark_to_string (error->domain), - error->code, error->message); - } else if (!dbus_g_error_has_name (error, "org.freedesktop.systemd1.LoadFailed")) { - nm_log_warn (LOGD_DISPATCH, "(%u) failed to call dispatcher scripts: (%s) %s", - info->request_id, dbus_g_error_get_name (error), error->message); + if (_nm_dbus_error_has_name (error, "org.freedesktop.systemd1.LoadFailed")) { + g_dbus_error_strip_remote_error (error); + nm_log_warn (LOGD_DISPATCH, "(%u) failed to call dispatcher scripts: %s", + info->request_id, error->message); } else { - nm_log_dbg (LOGD_DISPATCH, "(%u) failed to call dispatcher scripts: (%s) %s", - info->request_id, dbus_g_error_get_name (error), error->message); + nm_log_dbg (LOGD_DISPATCH, "(%u) failed to call dispatcher scripts: %s", + info->request_id, error->message); } + g_clear_error (&error); } if (info->callback) info->callback (info->request_id, info->user_data); - g_clear_error (&error); - g_object_unref (proxy); + dispatcher_info_cleanup (info); } static const char *action_table[] = { @@ -391,7 +437,8 @@ dispatcher_idle_cb (gpointer user_data) static gboolean _dispatcher_call (DispatcherAction action, gboolean blocking, - NMConnection *connection, + NMSettingsConnection *settings_connection, + NMConnection *applied_connection, NMDevice *device, const char *vpn_iface, NMIP4Config *vpn_ip4_config, @@ -400,23 +447,24 @@ _dispatcher_call (DispatcherAction action, gpointer user_data, guint *out_call_id) { - DBusGProxy *proxy; - DBusGConnection *g_connection; - GHashTable *connection_hash; - GHashTable *connection_props; - GHashTable *device_props; - GHashTable *device_ip4_props; - GHashTable *device_ip6_props; - GHashTable *device_dhcp4_props; - GHashTable *device_dhcp6_props; - GHashTable *vpn_ip4_props; - GHashTable *vpn_ip6_props; + GVariant *connection_dict; + GVariantBuilder connection_props; + GVariantBuilder device_props; + GVariantBuilder device_ip4_props; + GVariantBuilder device_ip6_props; + GVariant *device_dhcp4_props = NULL; + GVariant *device_dhcp6_props = NULL; + GVariantBuilder vpn_ip4_props; + GVariantBuilder vpn_ip6_props; DispatchInfo *info = NULL; gboolean success = FALSE; GError *error = NULL; static guint request_counter = 0; guint reqid = ++request_counter; + if (!dispatcher_proxy) + return FALSE; + /* Wrapping protection */ if (G_UNLIKELY (!reqid)) reqid = ++request_counter; @@ -459,87 +507,95 @@ _dispatcher_call (DispatcherAction action, goto done; } - g_connection = nm_dbus_manager_get_connection (nm_dbus_manager_get ()); - proxy = dbus_g_proxy_new_for_name (g_connection, - NM_DISPATCHER_DBUS_SERVICE, - NM_DISPATCHER_DBUS_PATH, - NM_DISPATCHER_DBUS_INTERFACE); - if (!proxy) { - nm_log_err (LOGD_DISPATCH, "(%u) could not get dispatcher proxy!", reqid); - return FALSE; - } + if (applied_connection) + connection_dict = nm_connection_to_dbus (applied_connection, NM_CONNECTION_SERIALIZE_NO_SECRETS); + else + connection_dict = g_variant_new_array (G_VARIANT_TYPE ("{sa{sv}}"), NULL, 0); - if (connection) { - GVariant *connection_dict; + g_variant_builder_init (&connection_props, G_VARIANT_TYPE_VARDICT); + if (settings_connection) { + const char *connection_path; const char *filename; - connection_dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_NO_SECRETS); - connection_hash = nm_utils_connection_dict_to_hash (connection_dict); - g_variant_unref (connection_dict); - - connection_props = value_hash_create (); - value_hash_add_object_path (connection_props, - NMD_CONNECTION_PROPS_PATH, - nm_connection_get_path (connection)); - filename = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection)); + connection_path = nm_connection_get_path (NM_CONNECTION (settings_connection)); + if (connection_path) { + g_variant_builder_add (&connection_props, "{sv}", + NMD_CONNECTION_PROPS_PATH, + g_variant_new_object_path (connection_path)); + } + filename = nm_settings_connection_get_filename (settings_connection); if (filename) { - value_hash_add_str (connection_props, - NMD_CONNECTION_PROPS_FILENAME, - filename); + g_variant_builder_add (&connection_props, "{sv}", + NMD_CONNECTION_PROPS_FILENAME, + g_variant_new_string (filename)); + } + if (nm_settings_connection_get_nm_generated_assumed (settings_connection)) { + g_variant_builder_add (&connection_props, "{sv}", + NMD_CONNECTION_PROPS_EXTERNAL, + g_variant_new_boolean (TRUE)); } - } else { - connection_hash = value_hash_create (); - connection_props = value_hash_create (); } - device_props = value_hash_create (); - device_ip4_props = value_hash_create (); - device_ip6_props = value_hash_create (); - device_dhcp4_props = value_hash_create (); - device_dhcp6_props = value_hash_create (); - vpn_ip4_props = value_hash_create (); - vpn_ip6_props = value_hash_create (); + g_variant_builder_init (&device_props, G_VARIANT_TYPE_VARDICT); + g_variant_builder_init (&device_ip4_props, G_VARIANT_TYPE_VARDICT); + g_variant_builder_init (&device_ip6_props, G_VARIANT_TYPE_VARDICT); + g_variant_builder_init (&vpn_ip4_props, G_VARIANT_TYPE_VARDICT); + g_variant_builder_init (&vpn_ip6_props, G_VARIANT_TYPE_VARDICT); /* hostname actions only send the hostname */ if (action != DISPATCHER_ACTION_HOSTNAME) { fill_device_props (device, - device_props, - device_ip4_props, - device_ip6_props, - device_dhcp4_props, - device_dhcp6_props); - if (vpn_ip4_config || vpn_ip6_config) - fill_vpn_props (vpn_ip4_config, vpn_ip6_config, vpn_ip4_props, vpn_ip6_props); + &device_props, + &device_ip4_props, + &device_ip6_props, + &device_dhcp4_props, + &device_dhcp6_props); + if (vpn_ip4_config || vpn_ip6_config) { + fill_vpn_props (vpn_ip4_config, + vpn_ip6_config, + &vpn_ip4_props, + &vpn_ip6_props); + } } + if (!device_dhcp4_props) + device_dhcp4_props = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0)); + if (!device_dhcp6_props) + device_dhcp6_props = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0)); + /* Send the action to the dispatcher */ if (blocking) { - GPtrArray *results = NULL; - - success = dbus_g_proxy_call_with_timeout (proxy, "Action", - CALL_TIMEOUT, - &error, - G_TYPE_STRING, action_to_string (action), - DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, connection_hash, - DBUS_TYPE_G_MAP_OF_VARIANT, connection_props, - DBUS_TYPE_G_MAP_OF_VARIANT, device_props, - DBUS_TYPE_G_MAP_OF_VARIANT, device_ip4_props, - DBUS_TYPE_G_MAP_OF_VARIANT, device_ip6_props, - DBUS_TYPE_G_MAP_OF_VARIANT, device_dhcp4_props, - DBUS_TYPE_G_MAP_OF_VARIANT, device_dhcp6_props, - G_TYPE_STRING, vpn_iface ? vpn_iface : "", - DBUS_TYPE_G_MAP_OF_VARIANT, vpn_ip4_props, - DBUS_TYPE_G_MAP_OF_VARIANT, vpn_ip6_props, - G_TYPE_BOOLEAN, nm_logging_enabled (LOGL_DEBUG, LOGD_DISPATCH), - G_TYPE_INVALID, - DISPATCHER_TYPE_RESULT_ARRAY, &results, - G_TYPE_INVALID); - if (success) { + GVariant *ret; + GVariantIter *results; + + ret = _nm_dbus_proxy_call_sync (dispatcher_proxy, "Action", + g_variant_new ("(s@a{sa{sv}}a{sv}a{sv}a{sv}a{sv}@a{sv}@a{sv}sa{sv}a{sv}b)", + action_to_string (action), + connection_dict, + &connection_props, + &device_props, + &device_ip4_props, + &device_ip6_props, + device_dhcp4_props, + device_dhcp6_props, + vpn_iface ? vpn_iface : "", + &vpn_ip4_props, + &vpn_ip6_props, + nm_logging_enabled (LOGL_DEBUG, LOGD_DISPATCH)), + G_VARIANT_TYPE ("(a(sus))"), + G_DBUS_CALL_FLAGS_NONE, CALL_TIMEOUT, + NULL, &error); + if (ret) { + g_variant_get (ret, "(a(sus))", &results); dispatcher_results_process (reqid, action, results); - free_results (results); + g_variant_iter_free (results); + g_variant_unref (ret); + success = TRUE; } else { - nm_log_warn (LOGD_DISPATCH, "(%u) failed: (%d) %s", reqid, error->code, error->message); - g_error_free (error); + g_dbus_error_strip_remote_error (error); + nm_log_warn (LOGD_DISPATCH, "(%u) failed: %s", reqid, error->message); + g_clear_error (&error); + success = FALSE; } } else { info = g_malloc0 (sizeof (*info)); @@ -547,36 +603,27 @@ _dispatcher_call (DispatcherAction action, info->request_id = reqid; info->callback = callback; info->user_data = user_data; - dbus_g_proxy_begin_call_with_timeout (proxy, "Action", - dispatcher_done_cb, - info, - (GDestroyNotify) dispatcher_info_cleanup, - CALL_TIMEOUT, - G_TYPE_STRING, action_to_string (action), - DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, connection_hash, - DBUS_TYPE_G_MAP_OF_VARIANT, connection_props, - DBUS_TYPE_G_MAP_OF_VARIANT, device_props, - DBUS_TYPE_G_MAP_OF_VARIANT, device_ip4_props, - DBUS_TYPE_G_MAP_OF_VARIANT, device_ip6_props, - DBUS_TYPE_G_MAP_OF_VARIANT, device_dhcp4_props, - DBUS_TYPE_G_MAP_OF_VARIANT, device_dhcp6_props, - G_TYPE_STRING, vpn_iface ? vpn_iface : "", - DBUS_TYPE_G_MAP_OF_VARIANT, vpn_ip4_props, - DBUS_TYPE_G_MAP_OF_VARIANT, vpn_ip6_props, - G_TYPE_BOOLEAN, nm_logging_enabled (LOGL_DEBUG, LOGD_DISPATCH), - G_TYPE_INVALID); + g_dbus_proxy_call (dispatcher_proxy, "Action", + g_variant_new ("(s@a{sa{sv}}a{sv}a{sv}a{sv}a{sv}@a{sv}@a{sv}sa{sv}a{sv}b)", + action_to_string (action), + connection_dict, + &connection_props, + &device_props, + &device_ip4_props, + &device_ip6_props, + device_dhcp4_props, + device_dhcp6_props, + vpn_iface ? vpn_iface : "", + &vpn_ip4_props, + &vpn_ip6_props, + nm_logging_enabled (LOGL_DEBUG, LOGD_DISPATCH)), + G_DBUS_CALL_FLAGS_NONE, CALL_TIMEOUT, + NULL, dispatcher_done_cb, info); success = TRUE; } - g_hash_table_destroy (connection_hash); - g_hash_table_destroy (connection_props); - g_hash_table_destroy (device_props); - g_hash_table_destroy (device_ip4_props); - g_hash_table_destroy (device_ip6_props); - g_hash_table_destroy (device_dhcp4_props); - g_hash_table_destroy (device_dhcp6_props); - g_hash_table_destroy (vpn_ip4_props); - g_hash_table_destroy (vpn_ip6_props); + g_variant_unref (device_dhcp4_props); + g_variant_unref (device_dhcp6_props); done: if (success && info) { @@ -593,7 +640,8 @@ done: /** * nm_dispatcher_call: * @action: the %DispatcherAction - * @connection: the #NMConnection the action applies to + * @settings_connection: the #NMSettingsConnection the action applies to + * @applied_connection: the currently applied connection * @device: the #NMDevice the action applies to * @callback: a caller-supplied callback to execute when done * @user_data: caller-supplied pointer passed to @callback @@ -607,20 +655,22 @@ done: */ gboolean nm_dispatcher_call (DispatcherAction action, - NMConnection *connection, + NMSettingsConnection *settings_connection, + NMConnection *applied_connection, NMDevice *device, DispatcherFunc callback, gpointer user_data, guint *out_call_id) { - return _dispatcher_call (action, FALSE, connection, device, NULL, NULL, + return _dispatcher_call (action, FALSE, settings_connection, applied_connection, device, NULL, NULL, NULL, callback, user_data, out_call_id); } /** * nm_dispatcher_call_sync(): * @action: the %DispatcherAction - * @connection: the #NMConnection the action applies to + * @settings_connection: the #NMSettingsConnection the action applies to + * @applied_connection: the currently applied connection * @device: the #NMDevice the action applies to * * This method always invokes the dispatcher action synchronously and it may @@ -630,17 +680,19 @@ nm_dispatcher_call (DispatcherAction action, */ gboolean nm_dispatcher_call_sync (DispatcherAction action, - NMConnection *connection, + NMSettingsConnection *settings_connection, + NMConnection *applied_connection, NMDevice *device) { - return _dispatcher_call (action, TRUE, connection, device, NULL, NULL, + return _dispatcher_call (action, TRUE, settings_connection, applied_connection, device, NULL, NULL, NULL, NULL, NULL, NULL); } /** * nm_dispatcher_call_vpn(): * @action: the %DispatcherAction - * @connection: the #NMConnection the action applies to + * @settings_connection: the #NMSettingsConnection the action applies to + * @applied_connection: the currently applied connection * @parent_device: the parent #NMDevice of the VPN connection * @vpn_iface: the IP interface of the VPN tunnel, if any * @vpn_ip4_config: the #NMIP4Config of the VPN connection @@ -657,7 +709,8 @@ nm_dispatcher_call_sync (DispatcherAction action, */ gboolean nm_dispatcher_call_vpn (DispatcherAction action, - NMConnection *connection, + NMSettingsConnection *settings_connection, + NMConnection *applied_connection, NMDevice *parent_device, const char *vpn_iface, NMIP4Config *vpn_ip4_config, @@ -666,14 +719,15 @@ nm_dispatcher_call_vpn (DispatcherAction action, gpointer user_data, guint *out_call_id) { - return _dispatcher_call (action, FALSE, connection, parent_device, vpn_iface, + return _dispatcher_call (action, FALSE, settings_connection, applied_connection, parent_device, vpn_iface, vpn_ip4_config, vpn_ip6_config, callback, user_data, out_call_id); } /** * nm_dispatcher_call_vpn_sync(): * @action: the %DispatcherAction - * @connection: the #NMConnection the action applies to + * @settings_connection: the #NMSettingsConnection the action applies to + * @applied_connection: the currently applied connection * @parent_device: the parent #NMDevice of the VPN connection * @vpn_iface: the IP interface of the VPN tunnel, if any * @vpn_ip4_config: the #NMIP4Config of the VPN connection @@ -686,13 +740,14 @@ nm_dispatcher_call_vpn (DispatcherAction action, */ gboolean nm_dispatcher_call_vpn_sync (DispatcherAction action, - NMConnection *connection, + NMSettingsConnection *settings_connection, + NMConnection *applied_connection, NMDevice *parent_device, const char *vpn_iface, NMIP4Config *vpn_ip4_config, NMIP6Config *vpn_ip6_config) { - return _dispatcher_call (action, TRUE, connection, parent_device, vpn_iface, + return _dispatcher_call (action, TRUE, settings_connection, applied_connection, parent_device, vpn_iface, vpn_ip4_config, vpn_ip6_config, NULL, NULL, NULL); } @@ -768,6 +823,7 @@ nm_dispatcher_init (void) { GFile *file; guint i; + GError *error = NULL; for (i = 0; i < G_N_ELEMENTS (monitors); i++) { file = g_file_new_for_path (monitors[i].dir); @@ -778,5 +834,18 @@ nm_dispatcher_init (void) } g_object_unref (file); } + + dispatcher_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + NM_DISPATCHER_DBUS_SERVICE, + NM_DISPATCHER_DBUS_PATH, + NM_DISPATCHER_DBUS_INTERFACE, + NULL, &error); + if (!dispatcher_proxy) { + nm_log_err (LOGD_DISPATCH, "could not get dispatcher proxy! %s", error->message); + g_clear_error (&error); + } } diff --git a/src/nm-dispatcher.h b/src/nm-dispatcher.h index e93816b6..42dcdc46 100644 --- a/src/nm-dispatcher.h +++ b/src/nm-dispatcher.h @@ -22,10 +22,9 @@ #ifndef __NETWORKMANAGER_DISPATCHER_H__ #define __NETWORKMANAGER_DISPATCHER_H__ -#include #include -#include "nm-types.h" +#include "nm-default.h" #include "nm-connection.h" typedef enum { @@ -45,18 +44,21 @@ typedef enum { typedef void (*DispatcherFunc) (guint call_id, gpointer user_data); gboolean nm_dispatcher_call (DispatcherAction action, - NMConnection *connection, + NMSettingsConnection *settings_connection, + NMConnection *applied_connection, NMDevice *device, DispatcherFunc callback, gpointer user_data, guint *out_call_id); gboolean nm_dispatcher_call_sync (DispatcherAction action, - NMConnection *connection, + NMSettingsConnection *settings_connection, + NMConnection *applied_connection, NMDevice *device); gboolean nm_dispatcher_call_vpn (DispatcherAction action, - NMConnection *connection, + NMSettingsConnection *settings_connection, + NMConnection *applied_connection, NMDevice *parent_device, const char *vpn_iface, NMIP4Config *vpn_ip4_config, @@ -66,7 +68,8 @@ gboolean nm_dispatcher_call_vpn (DispatcherAction action, guint *out_call_id); gboolean nm_dispatcher_call_vpn_sync (DispatcherAction action, - NMConnection *connection, + NMSettingsConnection *settings_connection, + NMConnection *applied_connection, NMDevice *parent_device, const char *vpn_iface, NMIP4Config *vpn_ip4_config, diff --git a/src/nm-enum-types.c b/src/nm-enum-types.c index 1ff95970..1d087f52 100644 --- a/src/nm-enum-types.c +++ b/src/nm-enum-types.c @@ -3,13 +3,15 @@ /* Generated by glib-mkenums. Do not edit */ +#include "config.h" + #include "nm-enum-types.h" #include "nm-device-bond.h" #include "nm-device-bridge.h" #include "nm-device-ethernet.h" -#include "nm-device-gre.h" #include "nm-device-infiniband.h" +#include "nm-device-ip-tunnel.h" #include "nm-device-macvlan.h" #include "nm-device-tun.h" #include "nm-device-veth.h" @@ -20,11 +22,11 @@ #include "nm-dhcp-dhcpcd.h" #include "nm-dhcp-systemd.h" #include "nm-device.h" +#include "nm-lldp-listener.h" #include "nm-device-ethernet-utils.h" #include "nm-device-factory.h" #include "nm-device-generic.h" #include "nm-device-logging.h" -#include "nm-device-private.h" #include "nm-dhcp-client.h" #include "nm-dhcp-utils.h" #include "nm-dhcp-listener.h" @@ -42,21 +44,18 @@ #include "nm-platform-utils.h" #include "nmp-object.h" #include "wifi-utils-nl80211.h" -#include "wifi-utils-private.h" #include "wifi-utils.h" #include "nm-fake-rdisc.h" #include "nm-lndp-rdisc.h" #include "nm-rdisc.h" -#include "nm-rdisc-private.h" #include "nm-ppp-manager.h" #include "nm-ppp-status.h" #include "nm-agent-manager.h" #include "nm-inotify-helper.h" #include "nm-secret-agent.h" #include "nm-settings-connection.h" +#include "nm-settings-plugin.h" #include "nm-settings.h" -#include "nm-system-config-interface.h" -#include "common.h" #include "nm-keyfile-connection.h" #include "plugin.h" #include "reader.h" @@ -69,20 +68,21 @@ #include "nm-supplicant-types.h" #include "nm-vpn-connection.h" #include "nm-vpn-manager.h" -#include "nm-vpn-service.h" #include "nm-activation-request.h" #include "nm-active-connection.h" +#include "nm-audit-manager.h" +#include "nm-bus-manager.h" #include "nm-config.h" #include "nm-config-data.h" #include "nm-connection-provider.h" #include "nm-connectivity.h" -#include "nm-dbus-manager.h" #include "nm-dcb.h" #include "nm-route-manager.h" #include "nm-default-route-manager.h" #include "nm-dhcp4-config.h" #include "nm-dhcp6-config.h" #include "nm-dispatcher.h" +#include "nm-exported-object.h" #include "nm-firewall-manager.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" @@ -93,10 +93,8 @@ #include "nm-manager.h" #include "nm-multi-index.h" #include "nm-policy.h" -#include "nm-properties-changed-signal.h" #include "nm-rfkill-manager.h" #include "nm-session-monitor.h" -#include "nm-session-utils.h" #include "nm-sleep-monitor.h" #include "nm-types.h" #include "NetworkManagerUtils.h" @@ -123,33 +121,6 @@ nm_vlan_error_get_type (void) return g_define_type_id__volatile; } GType -nm_unmanaged_flags_get_type (void) -{ - static volatile gsize g_define_type_id__volatile = 0; - - if (g_once_init_enter (&g_define_type_id__volatile)) - { - static const GFlagsValue values[] = { - { NM_UNMANAGED_NONE, "NM_UNMANAGED_NONE", "nm-unmanaged-none" }, - { NM_UNMANAGED_DEFAULT, "NM_UNMANAGED_DEFAULT", "nm-unmanaged-default" }, - { NM_UNMANAGED_INTERNAL, "NM_UNMANAGED_INTERNAL", "nm-unmanaged-internal" }, - { NM_UNMANAGED_USER, "NM_UNMANAGED_USER", "nm-unmanaged-user" }, - { NM_UNMANAGED_PARENT, "NM_UNMANAGED_PARENT", "nm-unmanaged-parent" }, - { NM_UNMANAGED_EXTERNAL_DOWN, "NM_UNMANAGED_EXTERNAL_DOWN", "nm-unmanaged-external-down" }, - { NM_UNMANAGED_PLATFORM_INIT, "NM_UNMANAGED_PLATFORM_INIT", "nm-unmanaged-platform-init" }, - { __NM_UNMANAGED_LAST, "__NM_UNMANAGED_LAST", "--nm-unmanaged-last" }, - { NM_UNMANAGED_LAST, "NM_UNMANAGED_LAST", "nm-unmanaged-last" }, - { NM_UNMANAGED_ALL, "NM_UNMANAGED_ALL", "nm-unmanaged-all" }, - { 0, NULL, NULL } - }; - GType g_define_type_id = - g_flags_register_static (g_intern_static_string ("NMUnmanagedFlags"), values); - g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); - } - - return g_define_type_id__volatile; -} -GType nm_dhcp_state_get_type (void) { static volatile gsize g_define_type_id__volatile = 0; @@ -215,42 +186,40 @@ nm_dns_manager_resolv_conf_mode_get_type (void) return g_define_type_id__volatile; } GType -nm_dns_masq_status_get_type (void) +nm_dns_manager_resolv_conf_manager_get_type (void) { static volatile gsize g_define_type_id__volatile = 0; if (g_once_init_enter (&g_define_type_id__volatile)) { static const GEnumValue values[] = { - { NM_DNSMASQ_STATUS_UNKNOWN, "NM_DNSMASQ_STATUS_UNKNOWN", "unknown" }, - { NM_DNSMASQ_STATUS_DEAD, "NM_DNSMASQ_STATUS_DEAD", "dead" }, - { NM_DNSMASQ_STATUS_RUNNING, "NM_DNSMASQ_STATUS_RUNNING", "running" }, + { NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE, "NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE", "none" }, + { NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF, "NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF", "resolvconf" }, + { NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG, "NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG", "netconfig" }, { 0, NULL, NULL } }; GType g_define_type_id = - g_enum_register_static (g_intern_static_string ("NMDnsMasqStatus"), values); + g_enum_register_static (g_intern_static_string ("NMDnsManagerResolvConfManager"), values); g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); } return g_define_type_id__volatile; } GType -nm_platform_reason_get_type (void) +nm_dns_masq_status_get_type (void) { static volatile gsize g_define_type_id__volatile = 0; if (g_once_init_enter (&g_define_type_id__volatile)) { static const GEnumValue values[] = { - { NM_PLATFORM_REASON_NONE, "NM_PLATFORM_REASON_NONE", "nm-platform-reason-none" }, - { NM_PLATFORM_REASON_INTERNAL, "NM_PLATFORM_REASON_INTERNAL", "nm-platform-reason-internal" }, - { NM_PLATFORM_REASON_EXTERNAL, "NM_PLATFORM_REASON_EXTERNAL", "nm-platform-reason-external" }, - { NM_PLATFORM_REASON_CACHE_CHECK, "NM_PLATFORM_REASON_CACHE_CHECK", "nm-platform-reason-cache-check" }, - { _NM_PLATFORM_REASON_CACHE_CHECK_INTERNAL, "_NM_PLATFORM_REASON_CACHE_CHECK_INTERNAL", "-nm-platform-reason-cache-check-internal" }, + { NM_DNSMASQ_STATUS_UNKNOWN, "NM_DNSMASQ_STATUS_UNKNOWN", "unknown" }, + { NM_DNSMASQ_STATUS_DEAD, "NM_DNSMASQ_STATUS_DEAD", "dead" }, + { NM_DNSMASQ_STATUS_RUNNING, "NM_DNSMASQ_STATUS_RUNNING", "running" }, { 0, NULL, NULL } }; GType g_define_type_id = - g_enum_register_static (g_intern_static_string ("NMPlatformReason"), values); + g_enum_register_static (g_intern_static_string ("NMDnsMasqStatus"), values); g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); } @@ -399,85 +368,102 @@ nm_settings_connection_flags_get_type (void) return g_define_type_id__volatile; } GType -nm_system_config_interface_capabilities_get_type (void) +nm_settings_plugin_capabilities_get_type (void) { static volatile gsize g_define_type_id__volatile = 0; if (g_once_init_enter (&g_define_type_id__volatile)) { static const GEnumValue values[] = { - { NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE, "NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE", "none" }, - { NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS, "NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS", "modify-connections" }, - { NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME, "NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME", "modify-hostname" }, + { NM_SETTINGS_PLUGIN_CAP_NONE, "NM_SETTINGS_PLUGIN_CAP_NONE", "none" }, + { NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS, "NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS", "modify-connections" }, { 0, NULL, NULL } }; GType g_define_type_id = - g_enum_register_static (g_intern_static_string ("NMSystemConfigInterfaceCapabilities"), values); + g_enum_register_static (g_intern_static_string ("NMSettingsPluginCapabilities"), values); g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); } return g_define_type_id__volatile; } GType -nm_system_config_interface_prop_get_type (void) +nm_settings_plugin_prop_get_type (void) { static volatile gsize g_define_type_id__volatile = 0; if (g_once_init_enter (&g_define_type_id__volatile)) { static const GEnumValue values[] = { - { NM_SYSTEM_CONFIG_INTERFACE_PROP_FIRST, "NM_SYSTEM_CONFIG_INTERFACE_PROP_FIRST", "first" }, - { NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME, "NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME", "name" }, - { NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, "NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO", "info" }, - { NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES, "NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES", "capabilities" }, - { NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME, "NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME", "hostname" }, + { NM_SETTINGS_PLUGIN_PROP_FIRST, "NM_SETTINGS_PLUGIN_PROP_FIRST", "first" }, + { NM_SETTINGS_PLUGIN_PROP_NAME, "NM_SETTINGS_PLUGIN_PROP_NAME", "name" }, + { NM_SETTINGS_PLUGIN_PROP_INFO, "NM_SETTINGS_PLUGIN_PROP_INFO", "info" }, + { NM_SETTINGS_PLUGIN_PROP_CAPABILITIES, "NM_SETTINGS_PLUGIN_PROP_CAPABILITIES", "capabilities" }, { 0, NULL, NULL } }; GType g_define_type_id = - g_enum_register_static (g_intern_static_string ("NMSystemConfigInterfaceProp"), values); + g_enum_register_static (g_intern_static_string ("NMSettingsPluginProp"), values); g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); } return g_define_type_id__volatile; } GType -nm_ap_support_get_type (void) +nm_opt_type_get_type (void) { static volatile gsize g_define_type_id__volatile = 0; if (g_once_init_enter (&g_define_type_id__volatile)) { static const GEnumValue values[] = { - { AP_SUPPORT_UNKNOWN, "AP_SUPPORT_UNKNOWN", "unknown" }, - { AP_SUPPORT_NO, "AP_SUPPORT_NO", "no" }, - { AP_SUPPORT_YES, "AP_SUPPORT_YES", "yes" }, + { TYPE_INVALID, "TYPE_INVALID", "invalid" }, + { TYPE_INT, "TYPE_INT", "int" }, + { TYPE_BYTES, "TYPE_BYTES", "bytes" }, + { TYPE_UTF8, "TYPE_UTF8", "utf8" }, + { TYPE_KEYWORD, "TYPE_KEYWORD", "keyword" }, + { TYPE_STRING, "TYPE_STRING", "string" }, { 0, NULL, NULL } }; GType g_define_type_id = - g_enum_register_static (g_intern_static_string ("ApSupport"), values); + g_enum_register_static (g_intern_static_string ("OptType"), values); g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); } return g_define_type_id__volatile; } GType -nm_opt_type_get_type (void) +nm_supplicant_feature_get_type (void) { static volatile gsize g_define_type_id__volatile = 0; if (g_once_init_enter (&g_define_type_id__volatile)) { static const GEnumValue values[] = { - { TYPE_INVALID, "TYPE_INVALID", "invalid" }, - { TYPE_INT, "TYPE_INT", "int" }, - { TYPE_BYTES, "TYPE_BYTES", "bytes" }, - { TYPE_UTF8, "TYPE_UTF8", "utf8" }, - { TYPE_KEYWORD, "TYPE_KEYWORD", "keyword" }, - { TYPE_STRING, "TYPE_STRING", "string" }, + { NM_SUPPLICANT_FEATURE_UNKNOWN, "NM_SUPPLICANT_FEATURE_UNKNOWN", "unknown" }, + { NM_SUPPLICANT_FEATURE_NO, "NM_SUPPLICANT_FEATURE_NO", "no" }, + { NM_SUPPLICANT_FEATURE_YES, "NM_SUPPLICANT_FEATURE_YES", "yes" }, { 0, NULL, NULL } }; GType g_define_type_id = - g_enum_register_static (g_intern_static_string ("OptType"), values); + g_enum_register_static (g_intern_static_string ("NMSupplicantFeature"), values); + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} +GType +nm_supplicant_error_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) + { + static const GEnumValue values[] = { + { NM_SUPPLICANT_ERROR_UNKNOWN, "NM_SUPPLICANT_ERROR_UNKNOWN", "Unknown" }, + { NM_SUPPLICANT_ERROR_CONFIG, "NM_SUPPLICANT_ERROR_CONFIG", "Config" }, + { 0, NULL, NULL } + }; + GType g_define_type_id = + g_enum_register_static (g_intern_static_string ("NMSupplicantError"), values); g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); } @@ -519,9 +505,13 @@ nm_config_change_flags_get_type (void) { NM_CONFIG_CHANGE_SIGUSR2, "NM_CONFIG_CHANGE_SIGUSR2", "nm-config-change-sigusr2" }, { NM_CONFIG_CHANGE_CONFIG_FILES, "NM_CONFIG_CHANGE_CONFIG_FILES", "nm-config-change-config-files" }, { NM_CONFIG_CHANGE_VALUES, "NM_CONFIG_CHANGE_VALUES", "nm-config-change-values" }, + { NM_CONFIG_CHANGE_VALUES_USER, "NM_CONFIG_CHANGE_VALUES_USER", "nm-config-change-values-user" }, + { NM_CONFIG_CHANGE_VALUES_INTERN, "NM_CONFIG_CHANGE_VALUES_INTERN", "nm-config-change-values-intern" }, { NM_CONFIG_CHANGE_CONNECTIVITY, "NM_CONFIG_CHANGE_CONNECTIVITY", "nm-config-change-connectivity" }, { NM_CONFIG_CHANGE_NO_AUTO_DEFAULT, "NM_CONFIG_CHANGE_NO_AUTO_DEFAULT", "nm-config-change-no-auto-default" }, { NM_CONFIG_CHANGE_DNS_MODE, "NM_CONFIG_CHANGE_DNS_MODE", "nm-config-change-dns-mode" }, + { NM_CONFIG_CHANGE_RC_MANAGER, "NM_CONFIG_CHANGE_RC_MANAGER", "nm-config-change-rc-manager" }, + { NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG, "NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG", "nm-config-change-global-dns-config" }, { _NM_CONFIG_CHANGE_LAST, "_NM_CONFIG_CHANGE_LAST", "-nm-config-change-last" }, { NM_CONFIG_CHANGE_ALL, "NM_CONFIG_CHANGE_ALL", "nm-config-change-all" }, { 0, NULL, NULL } @@ -603,48 +593,6 @@ nm_auth_call_result_get_type (void) return g_define_type_id__volatile; } GType -nm_rf_kill_state_get_type (void) -{ - static volatile gsize g_define_type_id__volatile = 0; - - if (g_once_init_enter (&g_define_type_id__volatile)) - { - static const GEnumValue values[] = { - { RFKILL_UNBLOCKED, "RFKILL_UNBLOCKED", "unblocked" }, - { RFKILL_SOFT_BLOCKED, "RFKILL_SOFT_BLOCKED", "soft-blocked" }, - { RFKILL_HARD_BLOCKED, "RFKILL_HARD_BLOCKED", "hard-blocked" }, - { 0, NULL, NULL } - }; - GType g_define_type_id = - g_enum_register_static (g_intern_static_string ("RfKillState"), values); - g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); - } - - return g_define_type_id__volatile; -} -GType -nm_rf_kill_type_get_type (void) -{ - static volatile gsize g_define_type_id__volatile = 0; - - if (g_once_init_enter (&g_define_type_id__volatile)) - { - static const GEnumValue values[] = { - { RFKILL_TYPE_WLAN, "RFKILL_TYPE_WLAN", "wlan" }, - { RFKILL_TYPE_WWAN, "RFKILL_TYPE_WWAN", "wwan" }, - { RFKILL_TYPE_WIMAX, "RFKILL_TYPE_WIMAX", "wimax" }, - { RFKILL_TYPE_UNKNOWN, "RFKILL_TYPE_UNKNOWN", "unknown" }, - { RFKILL_TYPE_MAX, "RFKILL_TYPE_MAX", "max" }, - { 0, NULL, NULL } - }; - GType g_define_type_id = - g_enum_register_static (g_intern_static_string ("RfKillType"), values); - g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); - } - - return g_define_type_id__volatile; -} -GType nm_ip_config_source_get_type (void) { static volatile gsize g_define_type_id__volatile = 0; @@ -693,10 +641,13 @@ nm_link_type_get_type (void) { NM_LINK_TYPE_GRE, "NM_LINK_TYPE_GRE", "gre" }, { NM_LINK_TYPE_GRETAP, "NM_LINK_TYPE_GRETAP", "gretap" }, { NM_LINK_TYPE_IFB, "NM_LINK_TYPE_IFB", "ifb" }, + { NM_LINK_TYPE_IP6TNL, "NM_LINK_TYPE_IP6TNL", "ip6tnl" }, + { NM_LINK_TYPE_IPIP, "NM_LINK_TYPE_IPIP", "ipip" }, { NM_LINK_TYPE_LOOPBACK, "NM_LINK_TYPE_LOOPBACK", "loopback" }, { NM_LINK_TYPE_MACVLAN, "NM_LINK_TYPE_MACVLAN", "macvlan" }, { NM_LINK_TYPE_MACVTAP, "NM_LINK_TYPE_MACVTAP", "macvtap" }, { NM_LINK_TYPE_OPENVSWITCH, "NM_LINK_TYPE_OPENVSWITCH", "openvswitch" }, + { NM_LINK_TYPE_SIT, "NM_LINK_TYPE_SIT", "sit" }, { NM_LINK_TYPE_TAP, "NM_LINK_TYPE_TAP", "tap" }, { NM_LINK_TYPE_TUN, "NM_LINK_TYPE_TUN", "tun" }, { NM_LINK_TYPE_VETH, "NM_LINK_TYPE_VETH", "veth" }, @@ -706,6 +657,7 @@ nm_link_type_get_type (void) { NM_LINK_TYPE_BRIDGE, "NM_LINK_TYPE_BRIDGE", "bridge" }, { NM_LINK_TYPE_BOND, "NM_LINK_TYPE_BOND", "bond" }, { NM_LINK_TYPE_TEAM, "NM_LINK_TYPE_TEAM", "team" }, + { NM_LINK_TYPE_ANY, "NM_LINK_TYPE_ANY", "any" }, { 0, NULL, NULL } }; GType g_define_type_id = @@ -729,6 +681,15 @@ nm_pobject_type_get_type (void) { NMP_OBJECT_TYPE_IP6_ADDRESS, "NMP_OBJECT_TYPE_IP6_ADDRESS", "nmp-object-type-ip6-address" }, { NMP_OBJECT_TYPE_IP4_ROUTE, "NMP_OBJECT_TYPE_IP4_ROUTE", "nmp-object-type-ip4-route" }, { NMP_OBJECT_TYPE_IP6_ROUTE, "NMP_OBJECT_TYPE_IP6_ROUTE", "nmp-object-type-ip6-route" }, + { NMP_OBJECT_TYPE_LNK_GRE, "NMP_OBJECT_TYPE_LNK_GRE", "nmp-object-type-lnk-gre" }, + { NMP_OBJECT_TYPE_LNK_INFINIBAND, "NMP_OBJECT_TYPE_LNK_INFINIBAND", "nmp-object-type-lnk-infiniband" }, + { NMP_OBJECT_TYPE_LNK_IP6TNL, "NMP_OBJECT_TYPE_LNK_IP6TNL", "nmp-object-type-lnk-ip6tnl" }, + { NMP_OBJECT_TYPE_LNK_IPIP, "NMP_OBJECT_TYPE_LNK_IPIP", "nmp-object-type-lnk-ipip" }, + { NMP_OBJECT_TYPE_LNK_MACVLAN, "NMP_OBJECT_TYPE_LNK_MACVLAN", "nmp-object-type-lnk-macvlan" }, + { NMP_OBJECT_TYPE_LNK_MACVTAP, "NMP_OBJECT_TYPE_LNK_MACVTAP", "nmp-object-type-lnk-macvtap" }, + { NMP_OBJECT_TYPE_LNK_SIT, "NMP_OBJECT_TYPE_LNK_SIT", "nmp-object-type-lnk-sit" }, + { NMP_OBJECT_TYPE_LNK_VLAN, "NMP_OBJECT_TYPE_LNK_VLAN", "nmp-object-type-lnk-vlan" }, + { NMP_OBJECT_TYPE_LNK_VXLAN, "NMP_OBJECT_TYPE_LNK_VXLAN", "nmp-object-type-lnk-vxlan" }, { __NMP_OBJECT_TYPE_LAST, "__NMP_OBJECT_TYPE_LAST", "--nmp-object-type-last" }, { NMP_OBJECT_TYPE_MAX, "NMP_OBJECT_TYPE_MAX", "nmp-object-type-max" }, { 0, NULL, NULL } @@ -761,6 +722,25 @@ nm_ip_config_merge_flags_get_type (void) return g_define_type_id__volatile; } GType +nm_utils_error_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) + { + static const GEnumValue values[] = { + { NM_UTILS_ERROR_UNKNOWN, "NM_UTILS_ERROR_UNKNOWN", "Unknown" }, + { NM_UTILS_ERROR_CANCELLED_DISPOSING, "NM_UTILS_ERROR_CANCELLED_DISPOSING", "CancelledDisposing" }, + { 0, NULL, NULL } + }; + GType g_define_type_id = + g_enum_register_static (g_intern_static_string ("NMUtilsError"), values); + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} +GType nm_match_spec_match_type_get_type (void) { static volatile gsize g_define_type_id__volatile = 0; diff --git a/src/nm-enum-types.h b/src/nm-enum-types.h index 0997211e..4a85d966 100644 --- a/src/nm-enum-types.h +++ b/src/nm-enum-types.h @@ -12,18 +12,16 @@ G_BEGIN_DECLS GType nm_vlan_error_get_type (void) G_GNUC_CONST; #define NM_TYPE_VLAN_ERROR (nm_vlan_error_get_type ()) -GType nm_unmanaged_flags_get_type (void) G_GNUC_CONST; -#define NM_TYPE_UNMANAGED_FLAGS (nm_unmanaged_flags_get_type ()) GType nm_dhcp_state_get_type (void) G_GNUC_CONST; #define NM_TYPE_DHCP_STATE (nm_dhcp_state_get_type ()) GType nm_dns_ip_config_type_get_type (void) G_GNUC_CONST; #define NM_TYPE_DNS_IP_CONFIG_TYPE (nm_dns_ip_config_type_get_type ()) GType nm_dns_manager_resolv_conf_mode_get_type (void) G_GNUC_CONST; #define NM_TYPE_DNS_MANAGER_RESOLV_CONF_MODE (nm_dns_manager_resolv_conf_mode_get_type ()) +GType nm_dns_manager_resolv_conf_manager_get_type (void) G_GNUC_CONST; +#define NM_TYPE_DNS_MANAGER_RESOLV_CONF_MANAGER (nm_dns_manager_resolv_conf_manager_get_type ()) GType nm_dns_masq_status_get_type (void) G_GNUC_CONST; #define NM_TYPE_DNS_MASQ_STATUS (nm_dns_masq_status_get_type ()) -GType nm_platform_reason_get_type (void) G_GNUC_CONST; -#define NM_TYPE_PLATFORM_REASON (nm_platform_reason_get_type ()) GType nm_platform_signal_change_type_get_type (void) G_GNUC_CONST; #define NM_TYPE_PLATFORM_SIGNAL_CHANGE_TYPE (nm_platform_signal_change_type_get_type ()) GType nm_rdisc_dhcp_level_get_type (void) G_GNUC_CONST; @@ -36,14 +34,16 @@ GType nm_ppp_status_get_type (void) G_GNUC_CONST; #define NM_TYPE_PPP_STATUS (nm_ppp_status_get_type ()) GType nm_settings_connection_flags_get_type (void) G_GNUC_CONST; #define NM_TYPE_SETTINGS_CONNECTION_FLAGS (nm_settings_connection_flags_get_type ()) -GType nm_system_config_interface_capabilities_get_type (void) G_GNUC_CONST; -#define NM_TYPE_SYSTEM_CONFIG_INTERFACE_CAPABILITIES (nm_system_config_interface_capabilities_get_type ()) -GType nm_system_config_interface_prop_get_type (void) G_GNUC_CONST; -#define NM_TYPE_SYSTEM_CONFIG_INTERFACE_PROP (nm_system_config_interface_prop_get_type ()) -GType nm_ap_support_get_type (void) G_GNUC_CONST; -#define NM_TYPE_AP_SUPPORT (nm_ap_support_get_type ()) +GType nm_settings_plugin_capabilities_get_type (void) G_GNUC_CONST; +#define NM_TYPE_SETTINGS_PLUGIN_CAPABILITIES (nm_settings_plugin_capabilities_get_type ()) +GType nm_settings_plugin_prop_get_type (void) G_GNUC_CONST; +#define NM_TYPE_SETTINGS_PLUGIN_PROP (nm_settings_plugin_prop_get_type ()) GType nm_opt_type_get_type (void) G_GNUC_CONST; #define NM_TYPE_OPT_TYPE (nm_opt_type_get_type ()) +GType nm_supplicant_feature_get_type (void) G_GNUC_CONST; +#define NM_TYPE_SUPPLICANT_FEATURE (nm_supplicant_feature_get_type ()) +GType nm_supplicant_error_get_type (void) G_GNUC_CONST; +#define NM_TYPE_SUPPLICANT_ERROR (nm_supplicant_error_get_type ()) GType nm_config_get_value_flags_get_type (void) G_GNUC_CONST; #define NM_TYPE_CONFIG_GET_VALUE_FLAGS (nm_config_get_value_flags_get_type ()) GType nm_config_change_flags_get_type (void) G_GNUC_CONST; @@ -54,10 +54,6 @@ GType nm_auth_subject_type_get_type (void) G_GNUC_CONST; #define NM_TYPE_AUTH_SUBJECT_TYPE (nm_auth_subject_type_get_type ()) GType nm_auth_call_result_get_type (void) G_GNUC_CONST; #define NM_TYPE_AUTH_CALL_RESULT (nm_auth_call_result_get_type ()) -GType nm_rf_kill_state_get_type (void) G_GNUC_CONST; -#define NM_TYPE_RF_KILL_STATE (nm_rf_kill_state_get_type ()) -GType nm_rf_kill_type_get_type (void) G_GNUC_CONST; -#define NM_TYPE_RF_KILL_TYPE (nm_rf_kill_type_get_type ()) GType nm_ip_config_source_get_type (void) G_GNUC_CONST; #define NM_TYPE_IP_CONFIG_SOURCE (nm_ip_config_source_get_type ()) GType nm_link_type_get_type (void) G_GNUC_CONST; @@ -66,6 +62,8 @@ GType nm_pobject_type_get_type (void) G_GNUC_CONST; #define NM_TYPE_POBJECT_TYPE (nm_pobject_type_get_type ()) GType nm_ip_config_merge_flags_get_type (void) G_GNUC_CONST; #define NM_TYPE_IP_CONFIG_MERGE_FLAGS (nm_ip_config_merge_flags_get_type ()) +GType nm_utils_error_get_type (void) G_GNUC_CONST; +#define NM_TYPE_UTILS_ERROR (nm_utils_error_get_type ()) GType nm_match_spec_match_type_get_type (void) G_GNUC_CONST; #define NM_TYPE_MATCH_SPEC_MATCH_TYPE (nm_match_spec_match_type_get_type ()) GType nm_utils_test_flags_get_type (void) G_GNUC_CONST; diff --git a/src/nm-exported-object.c b/src/nm-exported-object.c new file mode 100644 index 00000000..ca3187e8 --- /dev/null +++ b/src/nm-exported-object.c @@ -0,0 +1,883 @@ +/* -*- 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 2014-2015 Red Hat, Inc. + */ + +#include "config.h" + +#include +#include + +#include "nm-exported-object.h" +#include "nm-bus-manager.h" +#include "nm-default.h" + +static GHashTable *prefix_counters; +static gboolean quitting = FALSE; + + +#if NM_MORE_ASSERTS >= 2 +#define _ASSERT_NO_EARLY_EXPORT +#endif + +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (NMExportedObject, nm_exported_object, G_TYPE_DBUS_OBJECT_SKELETON, + prefix_counters = g_hash_table_new (g_str_hash, g_str_equal); + ) + +typedef struct { + GSList *interfaces; + + NMBusManager *bus_mgr; + char *path; + + GVariantBuilder pending_notifies; + guint notify_idle_id; + +#ifdef _ASSERT_NO_EARLY_EXPORT + gboolean _constructed; +#endif +} NMExportedObjectPrivate; + +#define NM_EXPORTED_OBJECT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_EXPORTED_OBJECT, NMExportedObjectPrivate)) + +typedef struct { + GHashTable *properties; + GSList *skeleton_types; + GArray *methods; +} NMExportedObjectClassInfo; + +GQuark nm_exported_object_class_info_quark (void); +G_DEFINE_QUARK (NMExportedObjectClassInfo, nm_exported_object_class_info) + +/*****************************************************************************/ + +#define _NMLOG_PREFIX_NAME "exported-object" +#define _NMLOG_DOMAIN LOGD_CORE + +#define _NMLOG(level, ...) \ + nm_log (level, _NMLOG_DOMAIN, \ + "%s[%p]: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, (self) \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)) + +/*****************************************************************************/ + +/* "AddConnectionUnsaved" -> "handle-add-connection-unsaved" */ +char * +nm_exported_object_skeletonify_method_name (const char *dbus_method_name) +{ + GString *out; + const char *p; + + out = g_string_new ("handle"); + for (p = dbus_method_name; *p; p++) { + if (g_ascii_isupper (*p) || p == dbus_method_name) { + g_string_append_c (out, '-'); + g_string_append_c (out, g_ascii_tolower (*p)); + } else + g_string_append_c (out, *p); + } + + return g_string_free (out, FALSE); +} + +/* "can-modify" -> "CanModify" */ +static char * +dbusify_name (const char *gobject_name) +{ + GString *out; + const char *p; + gboolean capitalize = TRUE; + + out = g_string_new (""); + for (p = gobject_name; *p; p++) { + if (capitalize) { + g_string_append_c (out, g_ascii_toupper (*p)); + capitalize = FALSE; + } else if (*p == '-') + capitalize = TRUE; + else + g_string_append_c (out, *p); + } + + return g_string_free (out, FALSE); +} + +/* "can_modify" -> "can-modify". Returns %NULL if @gobject_name contains no underscores */ +static char * +hyphenify_name (const char *gobject_name) +{ + char *hyphen_name, *p; + + if (!strchr (gobject_name, '_')) + return NULL; + + hyphen_name = g_strdup (gobject_name); + for (p = hyphen_name; *p; p++) { + if (*p == '_') + *p = '-'; + } + return hyphen_name; +} + +/* Called when an #NMExportedObject emits a signal that corresponds to a D-Bus + * signal, and re-emits that signal on the correct skeleton object as well. + */ +static gboolean +nm_exported_object_signal_hook (GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer data) +{ + NMExportedObject *self = g_value_get_object (¶m_values[0]); + NMExportedObjectPrivate *priv; + GSignalQuery *signal_info = data; + GDBusInterfaceSkeleton *interface = NULL; + GSList *iter; + GValue *dbus_param_values; + int i; + + priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + if (!priv->path) + return TRUE; + + for (iter = priv->interfaces; iter; iter = iter->next) { + if (g_type_is_a (G_OBJECT_TYPE (iter->data), signal_info->itype)) { + interface = G_DBUS_INTERFACE_SKELETON (iter->data); + break; + } + } + g_return_val_if_fail (interface != NULL, TRUE); + + dbus_param_values = g_new0 (GValue, n_param_values); + g_value_init (&dbus_param_values[0], G_OBJECT_TYPE (interface)); + g_value_set_object (&dbus_param_values[0], interface); + for (i = 1; i < n_param_values; i++) { + if (g_type_is_a (param_values[i].g_type, NM_TYPE_EXPORTED_OBJECT)) { + NMExportedObject *arg = g_value_get_object (¶m_values[i]); + + g_value_init (&dbus_param_values[i], G_TYPE_STRING); + if (arg && nm_exported_object_is_exported (arg)) + g_value_set_string (&dbus_param_values[i], nm_exported_object_get_path (arg)); + else + g_value_set_string (&dbus_param_values[i], "/"); + } else { + g_value_init (&dbus_param_values[i], param_values[i].g_type); + g_value_copy (¶m_values[i], &dbus_param_values[i]); + } + } + + g_signal_emitv (dbus_param_values, signal_info->signal_id, 0, NULL); + + for (i = 0; i < n_param_values; i++) + g_value_unset (&dbus_param_values[i]); + g_free (dbus_param_values); + + return TRUE; +} + +/** + * nm_exported_object_class_add_interface: + * @object_class: an #NMExportedObjectClass + * @dbus_skeleton_type: the type of the #GDBusInterfaceSkeleton to add + * @...: method name / handler pairs, %NULL-terminated + * + * Adds @dbus_skeleton_type to the list of D-Bus interfaces implemented by + * @object_class. Instances of @object_class will automatically have a skeleton + * of that type created, which will be exported when you call + * nm_exported_object_export(). + * + * The skeleton's properties will be initialized from the #NMExportedObject's, + * and bidirectional bindings will be set up between them. When exported + * properties change, both the org.freedesktop.DBus.Properties.PropertiesChanged + * signal and the traditional NetworkManager PropertiesChanged signal will be + * emitted. + * + * When a signal is emitted on an #NMExportedObject that has the same name as a + * signal on @dbus_skeleton_type, it will automatically be emitted on the + * skeleton as well; #NMExportedObject arguments in the signal will be converted + * to D-Bus object paths in the skeleton signal. + * + * The arguments after @dbus_skeleton_type are pairs of D-Bus method names (in + * CamelCase), and the corresponding handlers for them (which must have the same + * prototype as the corresponding "handle-..." signal on @dbus_skeleton_type, + * except with no return value, and with the first argument being an object of + * @object_class's type, not of @dbus_skeleton_type). + * + * It is a programmer error if: + * - @object_class does not define a property of the same name and type as + * each of @dbus_skeleton_type's properties. + * - @object_class does not define a signal with the same name and arguments + * as each of @dbus_skeleton_type's signals. + * - the list of method names includes any names that do not correspond to + * "handle-" signals on @dbus_skeleton_type. + * - the list of method names does not include every method defined by + * @dbus_skeleton_type. + */ +void +nm_exported_object_class_add_interface (NMExportedObjectClass *object_class, + GType dbus_skeleton_type, + ...) +{ + NMExportedObjectClassInfo *classinfo; + NMExportedObjectDBusMethodImpl method; + va_list ap; + const char *method_name; + GCallback impl; + gs_free GType *interfaces = NULL; + guint n_interfaces; + guint n_signals, n_method_signals; + guint object_signal_id; + GSignalQuery query; + int i, s; + GObjectClass *dbus_object_class; + gs_free GParamSpec **dbus_properties = NULL; + GParamSpec *object_property; + guint n_dbus_properties; + + g_return_if_fail (NM_IS_EXPORTED_OBJECT_CLASS (object_class)); + g_return_if_fail (g_type_is_a (dbus_skeleton_type, G_TYPE_DBUS_INTERFACE_SKELETON)); + + classinfo = g_slice_new (NMExportedObjectClassInfo); + classinfo->skeleton_types = NULL; + classinfo->methods = g_array_new (FALSE, FALSE, sizeof (NMExportedObjectDBusMethodImpl)); + classinfo->properties = g_hash_table_new (g_str_hash, g_str_equal); + g_type_set_qdata (G_TYPE_FROM_CLASS (object_class), + nm_exported_object_class_info_quark (), classinfo); + + classinfo->skeleton_types = g_slist_prepend (classinfo->skeleton_types, + GSIZE_TO_POINTER (dbus_skeleton_type)); + + /* Ensure @dbus_skeleton_type's class_init has run, so its signals/properties + * will be defined. + */ + dbus_object_class = g_type_class_ref (dbus_skeleton_type); + + /* Add method implementations from the varargs */ + va_start (ap, dbus_skeleton_type); + while ((method_name = va_arg (ap, const char *)) && (impl = va_arg (ap, GCallback))) { + method.dbus_skeleton_type = dbus_skeleton_type; + method.method_name = nm_exported_object_skeletonify_method_name (method_name); + g_assert (g_signal_lookup (method.method_name, dbus_skeleton_type) != 0); + method.impl = impl; + + g_array_append_val (classinfo->methods, method); + } + va_end (ap); + + /* Properties */ + dbus_properties = g_object_class_list_properties (dbus_object_class, &n_dbus_properties); + for (i = 0; i < n_dbus_properties; i++) { + char *hyphen_name; + + if (g_str_has_prefix (dbus_properties[i]->name, "g-")) + continue; + + object_property = g_object_class_find_property (G_OBJECT_CLASS (object_class), + dbus_properties[i]->name); + g_assert (object_property != NULL); + g_assert (object_property->value_type == dbus_properties[i]->value_type); + + g_assert (!g_hash_table_contains (classinfo->properties, dbus_properties[i]->name)); + g_hash_table_insert (classinfo->properties, + g_strdup (dbus_properties[i]->name), + dbusify_name (dbus_properties[i]->name)); + hyphen_name = hyphenify_name (dbus_properties[i]->name); + if (hyphen_name) { + g_assert (!g_hash_table_contains (classinfo->properties, hyphen_name)); + g_hash_table_insert (classinfo->properties, + hyphen_name, + dbusify_name (dbus_properties[i]->name)); + } + } + + /* Signals. Unlike g_object_class_list_properties(), g_signal_list_ids() is + * "shallow", so we need to query each implemented gdbus-generated interface + * separately. + */ + interfaces = g_type_interfaces (dbus_skeleton_type, &n_interfaces); + n_method_signals = 0; + for (i = 0; i < n_interfaces; i++) { + gs_free guint *dbus_signals = NULL; + + dbus_signals = g_signal_list_ids (interfaces[i], &n_signals); + for (s = 0; s < n_signals; s++) { + g_signal_query (dbus_signals[s], &query); + + /* PropertiesChanged is handled specially */ + if (!strcmp (query.signal_name, "properties-changed")) + continue; + + if (g_str_has_prefix (query.signal_name, "handle-")) { + n_method_signals++; + continue; + } + + object_signal_id = g_signal_lookup (query.signal_name, G_TYPE_FROM_CLASS (object_class)); + g_assert (object_signal_id != 0); + + g_signal_add_emission_hook (object_signal_id, 0, + nm_exported_object_signal_hook, + g_memdup (&query, sizeof (query)), + g_free); + } + } + + g_assert_cmpint (n_method_signals, ==, classinfo->methods->len); + + g_type_class_unref (dbus_object_class); +} + +/* "meta-marshaller" that receives the skeleton "handle-foo" signal, replaces + * the skeleton object with an #NMExportedObject in the parameters, drops the + * user_data parameter, and adds a "TRUE" return value (indicating to gdbus that + * the signal was handled). + */ +static void +nm_exported_object_meta_marshal (GClosure *closure, GValue *return_value, + guint n_param_values, const GValue *param_values, + gpointer invocation_hint, gpointer marshal_data) +{ + GValue *local_param_values; + + local_param_values = g_new0 (GValue, n_param_values); + g_value_init (&local_param_values[0], G_TYPE_POINTER); + g_value_set_pointer (&local_param_values[0], closure->data); + memcpy (local_param_values + 1, param_values + 1, (n_param_values - 1) * sizeof (GValue)); + + g_cclosure_marshal_generic (closure, NULL, + n_param_values, local_param_values, + invocation_hint, + ((GCClosure *)closure)->callback); + g_value_set_boolean (return_value, TRUE); + + g_value_unset (&local_param_values[0]); + g_free (local_param_values); +} + +GQuark _skeleton_data_quark (void); +G_DEFINE_QUARK (skeleton-data, _skeleton_data); + +typedef struct { + GBinding **prop_bindings; + gulong *method_signals; +} SkeletonData; + +GDBusInterfaceSkeleton * +nm_exported_object_skeleton_create (GType dbus_skeleton_type, + GObjectClass *object_class, + const NMExportedObjectDBusMethodImpl *methods, + guint methods_len, + GObject *target) +{ + GDBusInterfaceSkeleton *interface; + gs_free GParamSpec **properties = NULL; + SkeletonData *skeleton_data; + guint n_properties; + guint i, j; + + interface = G_DBUS_INTERFACE_SKELETON (g_object_new (dbus_skeleton_type, NULL)); + + skeleton_data = g_slice_new (SkeletonData); + + /* Bind properties */ + properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (interface), &n_properties); + skeleton_data->prop_bindings = g_new (GBinding *, n_properties + 1); + for (i = 0, j = 0; i < n_properties; i++) { + GParamSpec *nm_property; + GBindingFlags flags; + GBinding *prop_binding; + + nm_property = g_object_class_find_property (object_class, properties[i]->name); + if (!nm_property) + continue; + + flags = G_BINDING_SYNC_CREATE; + if ( (nm_property->flags & G_PARAM_WRITABLE) + && !(nm_property->flags & G_PARAM_CONSTRUCT_ONLY)) + flags |= G_BINDING_BIDIRECTIONAL; + prop_binding = g_object_bind_property (target, properties[i]->name, + interface, properties[i]->name, + flags); + if (prop_binding) + skeleton_data->prop_bindings[j++] = prop_binding; + } + skeleton_data->prop_bindings[j++] = NULL; + + /* Bind methods */ + skeleton_data->method_signals = g_new (gulong, methods_len + 1); + for (i = 0, j = 0; i < methods_len; i++) { + const NMExportedObjectDBusMethodImpl *method = &methods[i]; + GClosure *closure; + gulong method_signal; + + /* ignore methods that are for a different skeleton-type. */ + if ( method->dbus_skeleton_type + && method->dbus_skeleton_type != dbus_skeleton_type) + continue; + + closure = g_cclosure_new_swap (method->impl, target, NULL); + g_closure_set_meta_marshal (closure, NULL, nm_exported_object_meta_marshal); + method_signal = g_signal_connect_closure (interface, method->method_name, closure, FALSE); + + if (method_signal != 0) + skeleton_data->method_signals[j++] = method_signal; + } + skeleton_data->method_signals[j++] = 0; + + g_object_set_qdata ((GObject *) interface, _skeleton_data_quark (), skeleton_data); + + return interface; +} + +static void +nm_exported_object_create_skeletons (NMExportedObject *self, + GType object_type) +{ + NMExportedObjectPrivate *priv; + GObjectClass *object_class; + NMExportedObjectClassInfo *classinfo; + GSList *iter; + GDBusInterfaceSkeleton *interface; + const NMExportedObjectDBusMethodImpl *methods; + guint methods_len; + + classinfo = g_type_get_qdata (object_type, nm_exported_object_class_info_quark ()); + if (!classinfo) + return; + + object_class = g_type_class_peek (object_type); + priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + methods = classinfo->methods->len ? &g_array_index (classinfo->methods, NMExportedObjectDBusMethodImpl, 0) : NULL; + methods_len = classinfo->methods->len; + + for (iter = classinfo->skeleton_types; iter; iter = iter->next) { + interface = nm_exported_object_skeleton_create (GPOINTER_TO_SIZE (iter->data), + object_class, + methods, + methods_len, + (GObject *) self); + + g_dbus_object_skeleton_add_interface ((GDBusObjectSkeleton *) self, interface); + + priv->interfaces = g_slist_prepend (priv->interfaces, interface); + } +} + +void +nm_exported_object_skeleton_release (GDBusInterfaceSkeleton *interface) +{ + SkeletonData *skeleton_data; + guint j; + + g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface)); + + skeleton_data = g_object_steal_qdata ((GObject *) interface, _skeleton_data_quark ()); + + for (j = 0; skeleton_data->prop_bindings[j]; j++) + g_object_unref (skeleton_data->prop_bindings[j]); + for (j = 0; skeleton_data->method_signals[j]; j++) + g_signal_handler_disconnect (interface, skeleton_data->method_signals[j]); + + g_free (skeleton_data->prop_bindings); + g_free (skeleton_data->method_signals); + g_slice_free (SkeletonData, skeleton_data); + + g_object_unref (interface); +} + +static void +nm_exported_object_destroy_skeletons (NMExportedObject *self) +{ + NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + g_return_if_fail (priv->interfaces); + + while (priv->interfaces) { + GDBusInterfaceSkeleton *interface = priv->interfaces->data; + + priv->interfaces = g_slist_delete_link (priv->interfaces, priv->interfaces); + g_dbus_object_skeleton_remove_interface ((GDBusObjectSkeleton *) self, interface); + nm_exported_object_skeleton_release (interface); + } +} + +/** + * nm_exported_object_export: + * @self: an #NMExportedObject + * + * Exports @self on all active and future D-Bus connections. + * + * The path to export @self on is taken from its #NMObjectClass's %export_path + * member. If the %export_path contains "%u", then it will be replaced with a + * monotonically increasing integer ID (with each distinct %export_path having + * its own counter). Otherwise, %export_path will be used literally (implying + * that @self must be a singleton). + * + * Returns: the path @self was exported under + */ +const char * +nm_exported_object_export (NMExportedObject *self) +{ + NMExportedObjectPrivate *priv; + const char *class_export_path, *p; + GType type; + + g_return_val_if_fail (NM_IS_EXPORTED_OBJECT (self), NULL); + priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + g_return_val_if_fail (!priv->path, priv->path); + g_return_val_if_fail (!priv->bus_mgr, priv->path); + +#ifdef _ASSERT_NO_EARLY_EXPORT + nm_assert (priv->_constructed); +#endif + + priv->bus_mgr = nm_bus_manager_get (); + if (!priv->bus_mgr) + g_return_val_if_reached (NULL); + g_object_add_weak_pointer ((GObject *) priv->bus_mgr, (gpointer *) &priv->bus_mgr); + + class_export_path = NM_EXPORTED_OBJECT_GET_CLASS (self)->export_path; + p = strchr (class_export_path, '%'); + if (p) { + guint *counter; + + g_return_val_if_fail (p[1] == 'u', NULL); + g_return_val_if_fail (strchr (p + 1, '%') == NULL, NULL); + + counter = g_hash_table_lookup (prefix_counters, class_export_path); + if (!counter) { + counter = g_new0 (guint, 1); + g_hash_table_insert (prefix_counters, g_strdup (class_export_path), counter); + } + + priv->path = g_strdup_printf (class_export_path, (*counter)++); + } else + priv->path = g_strdup (class_export_path); + + _LOGT ("export: \"%s\"", priv->path); + g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (self), priv->path); + + type = G_OBJECT_TYPE (self); + while (type != NM_TYPE_EXPORTED_OBJECT) { + nm_exported_object_create_skeletons (self, type); + type = g_type_parent (type); + } + + /* Important: priv->path and priv->interfaces must not change while + * the object is registered. */ + + nm_bus_manager_register_object (priv->bus_mgr, (GDBusObjectSkeleton *) self); + + return priv->path; +} + +/** + * nm_exported_object_get_path: + * @self: an #NMExportedObject + * + * Gets @self's D-Bus path. + * + * Returns: @self's D-Bus path, or %NULL if @self is not exported. + */ +const char * +nm_exported_object_get_path (NMExportedObject *self) +{ + g_return_val_if_fail (NM_IS_EXPORTED_OBJECT (self), NULL); + + return NM_EXPORTED_OBJECT_GET_PRIVATE (self)->path; +} + +/** + * nm_exported_object_is_exported: + * @self: an #NMExportedObject + * + * Checks if @self is exported + * + * Returns: %TRUE if @self is exported + */ +gboolean +nm_exported_object_is_exported (NMExportedObject *self) +{ + g_return_val_if_fail (NM_IS_EXPORTED_OBJECT (self), FALSE); + + return NM_EXPORTED_OBJECT_GET_PRIVATE (self)->path != NULL; +} + +/** + * nm_exported_object_unexport: + * @self: an #NMExportedObject + * + * Unexports @self on all active D-Bus connections (and prevents it from being + * auto-exported on future connections). + */ +void +nm_exported_object_unexport (NMExportedObject *self) +{ + NMExportedObjectPrivate *priv; + + g_return_if_fail (NM_IS_EXPORTED_OBJECT (self)); + priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + g_return_if_fail (priv->path); + + /* Important: priv->path and priv->interfaces must not change while + * the object is registered. */ + + _LOGT ("unexport: \"%s\"", priv->path); + + if (priv->bus_mgr) { + nm_bus_manager_unregister_object (priv->bus_mgr, (GDBusObjectSkeleton *) self); + g_object_remove_weak_pointer ((GObject *) priv->bus_mgr, (gpointer *) &priv->bus_mgr); + priv->bus_mgr = NULL; + } + + nm_exported_object_destroy_skeletons (self); + + g_dbus_object_skeleton_set_object_path ((GDBusObjectSkeleton *) self, NULL); + + g_clear_pointer (&priv->path, g_free); + + if (nm_clear_g_source (&priv->notify_idle_id)) { + /* We had a notification queued. Since we removed all interfaces, + * the notification is obsolete and must be cleaned up. */ + g_variant_builder_clear (&priv->pending_notifies); + g_variant_builder_init (&priv->pending_notifies, G_VARIANT_TYPE_VARDICT); + } +} + +GSList * +nm_exported_object_get_interfaces (NMExportedObject *self) +{ + NMExportedObjectPrivate *priv; + + g_return_val_if_fail (NM_IS_EXPORTED_OBJECT (self), NULL); + + priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + g_return_val_if_fail (priv->path, NULL); + g_return_val_if_fail (priv->interfaces, NULL); + + return priv->interfaces; +} + +GDBusInterfaceSkeleton * +nm_exported_object_get_interface_by_type (NMExportedObject *self, GType interface_type) +{ + GSList *interfaces; + + interfaces = nm_exported_object_get_interfaces (self); + for (; interfaces; interfaces = interfaces->next) { + if (G_TYPE_CHECK_INSTANCE_TYPE (interfaces->data, interface_type)) + return interfaces->data; + } + return NULL; +} + +void +_nm_exported_object_clear_and_unexport (NMExportedObject **location) +{ + NMExportedObject *self; + NMExportedObjectPrivate *priv; + + if (!location || !*location) + return; + + self = *location; + *location = NULL; + + g_return_if_fail (NM_IS_EXPORTED_OBJECT (self)); + + priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + if (priv->path) + nm_exported_object_unexport (self); + + g_object_unref (self); +} + +static void +nm_exported_object_init (NMExportedObject *self) +{ + NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + + g_variant_builder_init (&priv->pending_notifies, G_VARIANT_TYPE_VARDICT); +} + +static gboolean +idle_emit_properties_changed (gpointer self) +{ + NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (self); + GVariant *notifies; + GSList *iter; + GDBusInterfaceSkeleton *interface = NULL; + guint signal_id = 0; + + priv->notify_idle_id = 0; + notifies = g_variant_builder_end (&priv->pending_notifies); + g_variant_ref_sink (notifies); + g_variant_builder_init (&priv->pending_notifies, G_VARIANT_TYPE_VARDICT); + + for (iter = priv->interfaces; iter; iter = iter->next) { + signal_id = g_signal_lookup ("properties-changed", G_OBJECT_TYPE (iter->data)); + if (signal_id != 0) { + interface = G_DBUS_INTERFACE_SKELETON (iter->data); + break; + } + } + g_return_val_if_fail (signal_id != 0, FALSE); + + if (nm_logging_enabled (LOGL_DEBUG, LOGD_DBUS_PROPS)) { + char *notification; + + notification = g_variant_print (notifies, TRUE); + nm_log_dbg (LOGD_DBUS_PROPS, "PropertiesChanged %s %p: %s", + G_OBJECT_TYPE_NAME (self), self, notification); + g_free (notification); + } + + g_signal_emit (interface, signal_id, 0, notifies); + g_variant_unref (notifies); + + return FALSE; +} + +static const GVariantType * +find_dbus_property_type (GDBusInterfaceSkeleton *skel, + const char *dbus_property_name) +{ + GDBusInterfaceInfo *iinfo; + int i; + + iinfo = g_dbus_interface_skeleton_get_info (skel); + for (i = 0; iinfo->properties[i]; i++) { + if (!strcmp (iinfo->properties[i]->name, dbus_property_name)) + return G_VARIANT_TYPE (iinfo->properties[i]->signature); + } + + return NULL; +} + +static void +nm_exported_object_notify (GObject *object, GParamSpec *pspec) +{ + NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (object); + NMExportedObjectClassInfo *classinfo; + GType type; + const char *dbus_property_name = NULL; + GValue value = G_VALUE_INIT; + const GVariantType *vtype; + GVariant *variant; + GSList *iter; + + if (!priv->interfaces) + return; + + for (type = G_OBJECT_TYPE (object); type; type = g_type_parent (type)) { + classinfo = g_type_get_qdata (type, nm_exported_object_class_info_quark ()); + if (!classinfo) + continue; + + dbus_property_name = g_hash_table_lookup (classinfo->properties, pspec->name); + if (dbus_property_name) + break; + } + if (!dbus_property_name) { + nm_log_trace (LOGD_DBUS_PROPS, "ignoring notification for prop %s on type %s", + pspec->name, G_OBJECT_TYPE_NAME (object)); + return; + } + + g_value_init (&value, pspec->value_type); + g_object_get_property (G_OBJECT (object), pspec->name, &value); + + vtype = NULL; + for (iter = priv->interfaces; iter && !vtype; iter = iter->next) + vtype = find_dbus_property_type (iter->data, dbus_property_name); + g_return_if_fail (vtype != NULL); + + variant = g_dbus_gvalue_to_gvariant (&value, vtype); + g_variant_builder_add (&priv->pending_notifies, "{sv}", + dbus_property_name, + variant); + g_value_unset (&value); + g_variant_unref (variant); + + if (!priv->notify_idle_id) + priv->notify_idle_id = g_idle_add (idle_emit_properties_changed, object); +} + +static void +constructed (GObject *object) +{ + NMExportedObjectClass *klass; + + G_OBJECT_CLASS (nm_exported_object_parent_class)->constructed (object); + +#ifdef _ASSERT_NO_EARLY_EXPORT + NM_EXPORTED_OBJECT_GET_PRIVATE (object)->_constructed = TRUE; +#endif + + klass = NM_EXPORTED_OBJECT_GET_CLASS (object); + + if (klass->export_on_construction) + nm_exported_object_export ((NMExportedObject *) object); +} + +static void +nm_exported_object_dispose (GObject *object) +{ + NMExportedObjectPrivate *priv = NM_EXPORTED_OBJECT_GET_PRIVATE (object); + + /* Objects should have already been unexported by their owner, unless + * we are quitting, where many objects stick around until exit. + */ + if (!quitting) { + if (priv->path) { + g_warn_if_reached (); + nm_exported_object_unexport (NM_EXPORTED_OBJECT (object)); + } + } else + g_clear_pointer (&priv->path, g_free); + + g_variant_builder_clear (&priv->pending_notifies); + nm_clear_g_source (&priv->notify_idle_id); + + G_OBJECT_CLASS (nm_exported_object_parent_class)->dispose (object); +} + +static void +nm_exported_object_class_init (NMExportedObjectClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (object_class, sizeof (NMExportedObjectPrivate)); + + object_class->constructed = constructed; + object_class->notify = nm_exported_object_notify; + object_class->dispose = nm_exported_object_dispose; +} + +void +nm_exported_object_class_set_quitting (void) +{ + quitting = TRUE; +} + diff --git a/src/nm-exported-object.h b/src/nm-exported-object.h new file mode 100644 index 00000000..88efb6fe --- /dev/null +++ b/src/nm-exported-object.h @@ -0,0 +1,85 @@ +/* -*- 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 2014 Red Hat, Inc. + */ + +#ifndef NM_EXPORTED_OBJECT_H +#define NM_EXPORTED_OBJECT_H + +#include "nm-default.h" + +G_BEGIN_DECLS + +/*****************************************************************************/ + +char *nm_exported_object_skeletonify_method_name (const char *dbus_method_name); + +typedef struct { + GType dbus_skeleton_type; + char *method_name; + GCallback impl; +} NMExportedObjectDBusMethodImpl; + +GDBusInterfaceSkeleton *nm_exported_object_skeleton_create (GType dbus_skeleton_type, + GObjectClass *object_class, + const NMExportedObjectDBusMethodImpl *methods, + guint methods_len, + GObject *target); +void nm_exported_object_skeleton_release (GDBusInterfaceSkeleton *interface); + +/*****************************************************************************/ + +#define NM_TYPE_EXPORTED_OBJECT (nm_exported_object_get_type ()) +#define NM_EXPORTED_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_EXPORTED_OBJECT, NMExportedObject)) +#define NM_EXPORTED_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_EXPORTED_OBJECT, NMExportedObjectClass)) +#define NM_IS_EXPORTED_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_EXPORTED_OBJECT)) +#define NM_IS_EXPORTED_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_EXPORTED_OBJECT)) +#define NM_EXPORTED_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_EXPORTED_OBJECT, NMExportedObjectClass)) + +struct _NMExportedObject { + GDBusObjectSkeleton parent; +}; + +typedef struct { + GDBusObjectSkeletonClass parent; + + const char *export_path; + char export_on_construction; +} NMExportedObjectClass; + +GType nm_exported_object_get_type (void); + +void nm_exported_object_class_set_quitting (void); + +void nm_exported_object_class_add_interface (NMExportedObjectClass *object_class, + GType dbus_skeleton_type, + ...) G_GNUC_NULL_TERMINATED; + +const char *nm_exported_object_export (NMExportedObject *self); +const char *nm_exported_object_get_path (NMExportedObject *self); +gboolean nm_exported_object_is_exported (NMExportedObject *self); +void nm_exported_object_unexport (NMExportedObject *self); +GSList * nm_exported_object_get_interfaces (NMExportedObject *self); +GDBusInterfaceSkeleton *nm_exported_object_get_interface_by_type (NMExportedObject *self, GType interface_type); + +void _nm_exported_object_clear_and_unexport (NMExportedObject **location); +#define nm_exported_object_clear_and_unexport(location) _nm_exported_object_clear_and_unexport ((NMExportedObject **) (location)) + +G_END_DECLS + +#endif /* NM_EXPORTED_OBJECT_H */ diff --git a/src/nm-firewall-manager.c b/src/nm-firewall-manager.c index 4d302e9d..5e5248a9 100644 --- a/src/nm-firewall-manager.c +++ b/src/nm-firewall-manager.c @@ -15,19 +15,17 @@ * 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. + * Copyright (C) 2011 - 2015 Red Hat, Inc. */ #include "config.h" #include -#include -#include -#include +#include "nm-default.h" #include "nm-firewall-manager.h" -#include "nm-dbus-manager.h" -#include "nm-logging.h" +#include "gsystem-local-alloc.h" +#include "NetworkManagerUtils.h" #define NM_FIREWALL_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ NM_TYPE_FIREWALL_MANAGER, \ @@ -43,12 +41,10 @@ enum { }; typedef struct { - NMDBusManager * dbus_mgr; - guint name_owner_id; - DBusGProxy * proxy; + GDBusProxy * proxy; gboolean running; - GSList *pending_calls; + GHashTable *pending_calls; } NMFirewallManagerPrivate; enum { @@ -59,246 +55,350 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; +NM_DEFINE_SINGLETON_GETTER (NMFirewallManager, nm_firewall_manager_get, NM_TYPE_FIREWALL_MANAGER); + /********************************************************************/ -#define PENDING_CALL_DUMMY ((NMFirewallPendingCall) GUINT_TO_POINTER(1)) -#define PENDING_CALL_FROM_INFO(info) ((NMFirewallPendingCall) info) +typedef enum { + CB_INFO_OPS_ADD = 1, + CB_INFO_OPS_CHANGE, + CB_INFO_OPS_REMOVE, +} CBInfoOpsType; -typedef struct { +typedef enum { + CB_INFO_MODE_IDLE = 1, + CB_INFO_MODE_DBUS, + CB_INFO_MODE_DBUS_COMPLETED, +} CBInfoMode; + +struct _NMFirewallManagerCallId { NMFirewallManager *self; + CBInfoOpsType ops_type; + CBInfoMode mode; char *iface; - FwAddToZoneFunc callback; + NMFirewallManagerAddRemoveCallback callback; gpointer user_data; - guint id; - gboolean completed; - - guint idle_id; - DBusGProxyCall *dbus_call; -} CBInfo; - -static void -_cb_info_free (CBInfo *info) -{ - NMFirewallManagerPrivate *priv; - g_return_if_fail (info != NULL); + union { + struct { + GCancellable *cancellable; + } dbus; + struct { + guint id; + } idle; + }; +}; +typedef struct _NMFirewallManagerCallId CBInfo; - if (!info->completed) { - nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone call cancelled [%u]", info->iface, info->id); - if (info->callback) { - GError *error; +/********************************************************************/ - error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED, - "Operation was cancelled"); - info->callback (error, info->user_data); - g_error_free (error); - } +static const char * +_ops_type_to_string (CBInfoOpsType ops_type) +{ + switch (ops_type) { + case CB_INFO_OPS_ADD: return "add"; + case CB_INFO_OPS_REMOVE: return "remove"; + case CB_INFO_OPS_CHANGE: return "change"; + default: g_return_val_if_reached ("unknown"); } - g_free (info->iface); +} - priv = NM_FIREWALL_MANAGER_GET_PRIVATE (info->self); - priv->pending_calls = g_slist_remove (priv->pending_calls, info); - g_object_unref (info->self); +#define _NMLOG_DOMAIN LOGD_FIREWALL +#define _NMLOG_PREFIX_NAME "firewall" +#define _NMLOG(level, info, ...) \ + G_STMT_START { \ + if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \ + CBInfo *__info = (info); \ + char __prefix_name[30]; \ + char __prefix_info[64]; \ + \ + _nm_log ((level), (_NMLOG_DOMAIN), 0, \ + "%s: %s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + (self) != singleton_instance \ + ? ({ \ + g_snprintf (__prefix_name, sizeof (__prefix_name), "%s[%p]", ""_NMLOG_PREFIX_NAME, (self)); \ + __prefix_name; \ + }) \ + : _NMLOG_PREFIX_NAME, \ + __info \ + ? ({ \ + g_snprintf (__prefix_info, sizeof (__prefix_info), "[%p,%s%s:%s%s%s]: ", __info, \ + _ops_type_to_string (__info->ops_type), _cb_info_is_idle (__info) ? "*" : "", \ + NM_PRINT_FMT_QUOTE_STRING (__info->iface)); \ + __prefix_info; \ + }) \ + : "" \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } G_STMT_END - g_slice_free (CBInfo, info); +/********************************************************************/ + +static gboolean +_cb_info_is_idle (CBInfo *info) +{ + return info->mode == CB_INFO_MODE_IDLE; } static CBInfo * -_cb_info_create (NMFirewallManager *self, const char *iface, FwAddToZoneFunc callback, gpointer user_data) +_cb_info_create (NMFirewallManager *self, + CBInfoOpsType ops_type, + const char *iface, + NMFirewallManagerAddRemoveCallback callback, + gpointer user_data) { NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); - static guint id; CBInfo *info; info = g_slice_new0 (CBInfo); - if (++id == 0) - ++id; info->self = g_object_ref (self); - info->id = id; + info->ops_type = ops_type; info->iface = g_strdup (iface); - info->completed = FALSE; info->callback = callback; info->user_data = user_data; - priv->pending_calls = g_slist_prepend (priv->pending_calls, info); + if (priv->running) { + info->mode = CB_INFO_MODE_DBUS; + info->dbus.cancellable = g_cancellable_new (); + } else + info->mode = CB_INFO_MODE_IDLE; + + if (!nm_g_hash_table_add (priv->pending_calls, info)) + g_return_val_if_reached (NULL); + return info; } +static void +_cb_info_free (CBInfo *info) +{ + if (!_cb_info_is_idle (info)) + g_object_unref (info->dbus.cancellable); + g_free (info->iface); + if (info->self) + g_object_unref (info->self); + g_slice_free (CBInfo, info); +} + +static void +_cb_info_callback (CBInfo *info, + GError *error) +{ + if (info->callback) + info->callback (info->self, info, error, info->user_data); +} + +static void +_cb_info_complete_normal (CBInfo *info, GError *error) +{ + NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (info->self); + + if (!g_hash_table_remove (priv->pending_calls, info)) + g_return_if_reached (); + + _cb_info_callback (info, error); + _cb_info_free (info); +} + static gboolean -add_or_change_idle_cb (gpointer user_data) +_handle_idle (gpointer user_data) { + NMFirewallManager *self; CBInfo *info = user_data; - if (info->idle_id == 0) { - /* operation was cancelled. _cb_info_free will invoke callback. */ - } else { - nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone call pretends success [%u]", - info->iface, info->id); - if (info->callback) - info->callback (NULL, info->user_data); - info->completed = TRUE; - info->idle_id = 0; - } + nm_assert (info && NM_IS_FIREWALL_MANAGER (info->self)); - _cb_info_free (info); + self = info->self; + + _LOGD (info, "complete: fake success"); + + _cb_info_complete_normal (info, NULL); return G_SOURCE_REMOVE; } static void -add_or_change_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) +_handle_dbus (GObject *proxy, GAsyncResult *result, gpointer user_data) { + NMFirewallManager *self; CBInfo *info = user_data; - GError *error = NULL; - char *zone = NULL; - - if (!dbus_g_proxy_end_call (proxy, call_id, &error, - G_TYPE_STRING, &zone, - G_TYPE_INVALID)) { - g_assert (error); - if (g_strcmp0 (error->message, "ZONE_ALREADY_SET") != 0) { - nm_log_warn (LOGD_FIREWALL, "(%s) firewall zone add/change failed [%u]: (%d) %s", - info->iface, info->id, error->code, error->message); - } else { - nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone add/change failed [%u]: (%d) %s", - info->iface, info->id, error->code, error->message); - } - } else { - nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone add/change succeeded [%u]", - info->iface, info->id); + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *ret = NULL; + + if (info->mode != CB_INFO_MODE_DBUS) { + _cb_info_free (info); + return; } - if (info->callback) - info->callback (error, info->user_data); + self = info->self; + + ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result, &error); - info->completed = TRUE; - g_free (zone); - g_clear_error (&error); + if (error) { + const char *non_error = NULL; + + g_dbus_error_strip_remote_error (error); + + switch (info->ops_type) { + case CB_INFO_OPS_ADD: + case CB_INFO_OPS_CHANGE: + non_error = "ZONE_ALREADY_SET"; + break; + case CB_INFO_OPS_REMOVE: + non_error = "UNKNOWN_INTERFACE"; + break; + } + if (!g_strcmp0 (error->message, non_error)) { + _LOGD (info, "complete: request failed with a non-error (%s)", error->message); + + /* The operation failed with an error reason that we don't want + * to propagate. Instead, signal success. */ + g_clear_error (&error); + } + else + _LOGW (info, "complete: request failed (%s)", error->message); + } else + _LOGD (info, "complete: success"); + + _cb_info_complete_normal (info, error); } -NMFirewallPendingCall -nm_firewall_manager_add_or_change_zone (NMFirewallManager *self, - const char *iface, - const char *zone, - gboolean add, /* TRUE == add, FALSE == change */ - FwAddToZoneFunc callback, - gpointer user_data) +static NMFirewallManagerCallId +_start_request (NMFirewallManager *self, + CBInfoOpsType ops_type, + const char *iface, + const char *zone, + NMFirewallManagerAddRemoveCallback callback, + gpointer user_data) { - NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); + NMFirewallManagerPrivate *priv; CBInfo *info; + const char *dbus_method; + + g_return_val_if_fail (NM_IS_FIREWALL_MANAGER (self), NULL); + g_return_val_if_fail (iface && *iface, NULL); + + priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); + + info = _cb_info_create (self, ops_type, iface, callback, user_data); + + _LOGD (info, "firewall zone %s %s:%s%s%s%s", + _ops_type_to_string (info->ops_type), + iface, + NM_PRINT_FMT_QUOTED (zone, "\"", zone, "\"", "default"), + _cb_info_is_idle (info) ? " (not running, simulate success)" : ""); + + if (!_cb_info_is_idle (info)) { + + switch (ops_type) { + case CB_INFO_OPS_ADD: + dbus_method = "addInterface"; + break; + case CB_INFO_OPS_CHANGE: + dbus_method = "changeZone"; + break; + case CB_INFO_OPS_REMOVE: + dbus_method = "removeInterface"; + break; + default: + g_assert_not_reached (); + } - if (priv->running == FALSE) { - if (callback) { - info = _cb_info_create (self, iface, callback, user_data); - info->idle_id = g_idle_add (add_or_change_idle_cb, info); - nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone %s -> %s%s%s [%u] (not running, simulate success)", iface, add ? "add" : "change", - zone?"\"":"", zone ? zone : "default", zone?"\"":"", info->id); - return PENDING_CALL_FROM_INFO (info); - } else { - nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone add/change skipped (not running)", iface); - return PENDING_CALL_DUMMY; + g_dbus_proxy_call (priv->proxy, + dbus_method, + g_variant_new ("(ss)", zone ? zone : "", iface), + G_DBUS_CALL_FLAGS_NONE, 10000, + info->dbus.cancellable, + _handle_dbus, + info); + + if (!info->callback) { + /* if the user did not provide a callback, the call_id is useless. + * Especially, the user cannot use the call-id to cancel the request, + * because he cannot know whether the request is still pending. + * + * Hence, returning %NULL doesn't mean that the request could not be started + * (the request will always be started). */ + return NULL; } - } + } else if (!info->callback) { + /* if the user did not provide a callback and firewalld is not running, + * there is no point in scheduling an idle-request to fake success. Just + * return right away. */ + _LOGD (info, "complete: drop request simulating success"); + _cb_info_complete_normal (info, NULL); + return NULL; + } else + info->idle.id = g_idle_add (_handle_idle, info); - info = _cb_info_create (self, iface, callback, user_data); - - nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone %s -> %s%s%s [%u]", iface, add ? "add" : "change", - zone?"\"":"", zone ? zone : "default", zone?"\"":"", info->id); - info->dbus_call = dbus_g_proxy_begin_call_with_timeout (priv->proxy, - add ? "addInterface" : "changeZone", - add_or_change_cb, - info, - (GDestroyNotify) _cb_info_free, - 10000, /* timeout */ - G_TYPE_STRING, zone ? zone : "", - G_TYPE_STRING, iface, - G_TYPE_INVALID); - return PENDING_CALL_FROM_INFO (info); + return info; } -static void -remove_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data) +NMFirewallManagerCallId +nm_firewall_manager_add_or_change_zone (NMFirewallManager *self, + const char *iface, + const char *zone, + gboolean add, /* TRUE == add, FALSE == change */ + NMFirewallManagerAddRemoveCallback callback, + gpointer user_data) { - CBInfo *info = user_data; - GError *error = NULL; - char * zone = NULL; - - if (!dbus_g_proxy_end_call (proxy, call_id, &error, - G_TYPE_STRING, &zone, - G_TYPE_INVALID)) { - g_assert (error); - /* ignore UNKNOWN_INTERFACE errors */ - if (error->message && !strstr (error->message, "UNKNOWN_INTERFACE")) { - nm_log_warn (LOGD_FIREWALL, "(%s) firewall zone remove failed [%u]: (%d) %s", - info->iface, info->id, error->code, error->message); - } else { - nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone remove failed [%u]: (%d) %s", - info->iface, info->id, error->code, error->message); - } - } else { - nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone remove succeeded [%u]", - info->iface, info->id); - } - - info->completed = TRUE; - g_free (zone); - g_clear_error (&error); + return _start_request (self, + add ? CB_INFO_OPS_ADD : CB_INFO_OPS_CHANGE, + iface, + zone, + callback, + user_data); } -NMFirewallPendingCall +NMFirewallManagerCallId nm_firewall_manager_remove_from_zone (NMFirewallManager *self, const char *iface, - const char *zone) + const char *zone, + NMFirewallManagerAddRemoveCallback callback, + gpointer user_data) { - NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); - CBInfo *info; - - if (priv->running == FALSE) { - nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone remove skipped (not running)", iface); - return PENDING_CALL_DUMMY; - } - - info = _cb_info_create (self, iface, NULL, NULL); - - nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone remove -> %s%s%s [%u]", iface, - zone?"\"":"", zone ? zone : "*", zone?"\"":"", info->id); - info->dbus_call = dbus_g_proxy_begin_call_with_timeout (priv->proxy, - "removeInterface", - remove_cb, - info, - (GDestroyNotify) _cb_info_free, - 10000, /* timeout */ - G_TYPE_STRING, zone ? zone : "", - G_TYPE_STRING, iface, - G_TYPE_INVALID); - return PENDING_CALL_FROM_INFO (info); + return _start_request (self, + CB_INFO_OPS_REMOVE, + iface, + zone, + callback, + user_data); } -void nm_firewall_manager_cancel_call (NMFirewallManager *self, NMFirewallPendingCall call) +void +nm_firewall_manager_cancel_call (NMFirewallManagerCallId call) { - NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); - GSList *pending; - CBInfo *info; + NMFirewallManager *self; + NMFirewallManagerPrivate *priv; + CBInfo *info = call; + gs_free_error GError *error = NULL; - g_return_if_fail (NM_IS_FIREWALL_MANAGER (self)); + g_return_if_fail (info); + g_return_if_fail (NM_IS_FIREWALL_MANAGER (info->self)); - if (call == PENDING_CALL_DUMMY) - return; + self = info->self; + priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); - pending = g_slist_find (priv->pending_calls, call); + if (!g_hash_table_remove (priv->pending_calls, info)) + g_return_if_reached (); - if (!pending) - return; - priv->pending_calls = g_slist_remove_link (priv->pending_calls, pending); - - info = (CBInfo *) call; - if (info->idle_id) - info->idle_id = 0; - else { - dbus_g_proxy_cancel_call (NM_FIREWALL_MANAGER_GET_PRIVATE (self)->proxy, - info->dbus_call); + nm_utils_error_set_cancelled (&error, FALSE, "NMFirewallManager"); + + _LOGD (info, "complete: cancel (%s)", error->message); + + _cb_info_callback (info, error); + + if (_cb_info_is_idle (info)) { + g_source_remove (info->idle.id); + _cb_info_free (info); + } else { + info->mode = CB_INFO_MODE_DBUS_COMPLETED; + g_cancellable_cancel (info->dbus.cancellable); + g_clear_object (&info->self); } } +/*******************************************************************/ + static void set_running (NMFirewallManager *self, gboolean now_running) { @@ -311,59 +411,62 @@ set_running (NMFirewallManager *self, gboolean now_running) } static void -name_owner_changed (NMDBusManager *dbus_mgr, - const char *name, - const char *old_owner, - const char *new_owner, - gpointer user_data) +name_owner_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) { NMFirewallManager *self = NM_FIREWALL_MANAGER (user_data); - gboolean old_owner_good = (old_owner && strlen (old_owner)); - gboolean new_owner_good = (new_owner && strlen (new_owner)); - - /* We only care about the firewall here */ - if (strcmp (FIREWALL_DBUS_SERVICE, name) != 0) - return; + gs_free char *owner = NULL; - if (!old_owner_good && new_owner_good) { - nm_log_dbg (LOGD_FIREWALL, "firewall started"); + owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object)); + if (owner) { + _LOGD (NULL, "firewall started"); set_running (self, TRUE); g_signal_emit (self, signals[STARTED], 0); - } else if (old_owner_good && !new_owner_good) { - nm_log_dbg (LOGD_FIREWALL, "firewall stopped"); + } else { + _LOGD (NULL, "firewall stopped"); set_running (self, FALSE); } } /*******************************************************************/ -NM_DEFINE_SINGLETON_GETTER (NMFirewallManager, nm_firewall_manager_get, NM_TYPE_FIREWALL_MANAGER); - static void nm_firewall_manager_init (NMFirewallManager * self) { NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); - DBusGConnection *bus; - - priv->dbus_mgr = g_object_ref (nm_dbus_manager_get ()); - priv->name_owner_id = g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_NAME_OWNER_CHANGED, - G_CALLBACK (name_owner_changed), - self); - priv->running = nm_dbus_manager_name_has_owner (priv->dbus_mgr, FIREWALL_DBUS_SERVICE); - nm_log_dbg (LOGD_FIREWALL, "firewall %s running", priv->running ? "is" : "is not" ); - - bus = nm_dbus_manager_get_connection (priv->dbus_mgr); - priv->proxy = dbus_g_proxy_new_for_name (bus, - FIREWALL_DBUS_SERVICE, - FIREWALL_DBUS_PATH, - FIREWALL_DBUS_INTERFACE_ZONE); + + priv->pending_calls = g_hash_table_new (g_direct_hash, g_direct_equal); } static void -set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +constructed (GObject *object) { - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + NMFirewallManager *self = (NMFirewallManager *) object; + NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); + gs_free char *owner = NULL; + gs_free_error GError *error = NULL; + + G_OBJECT_CLASS (nm_firewall_manager_parent_class)->constructed (object); + + priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + FIREWALL_DBUS_SERVICE, + FIREWALL_DBUS_PATH, + FIREWALL_DBUS_INTERFACE_ZONE, + NULL, &error); + if (priv->proxy) { + g_signal_connect (priv->proxy, "notify::g-name-owner", + G_CALLBACK (name_owner_changed), self); + owner = g_dbus_proxy_get_name_owner (priv->proxy); + priv->running = (owner != NULL); + } else { + _LOGW (NULL, "could not connect to system D-Bus (%s)", error->message); + } + + _LOGD (NULL, "firewall constructed (%srunning)", priv->running ? "" : "not"); } static void @@ -382,14 +485,15 @@ get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) static void dispose (GObject *object) { - NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (object); - - g_assert (priv->pending_calls == NULL); + NMFirewallManager *self = NM_FIREWALL_MANAGER (object); + NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self); - if (priv->dbus_mgr) { - g_signal_handler_disconnect (priv->dbus_mgr, priv->name_owner_id); - priv->name_owner_id = 0; - g_clear_object (&priv->dbus_mgr); + if (priv->pending_calls) { + /* as every pending operation takes a reference to the manager, + * we don't expect pending operations at this point. */ + g_assert (g_hash_table_size (priv->pending_calls) == 0); + g_hash_table_unref (priv->pending_calls); + priv->pending_calls = NULL; } g_clear_object (&priv->proxy); @@ -405,25 +509,25 @@ nm_firewall_manager_class_init (NMFirewallManagerClass *klass) g_type_class_add_private (object_class, sizeof (NMFirewallManagerPrivate)); + object_class->constructed = constructed; object_class->get_property = get_property; - object_class->set_property = set_property; object_class->dispose = dispose; g_object_class_install_property - (object_class, PROP_AVAILABLE, - g_param_spec_boolean (NM_FIREWALL_MANAGER_AVAILABLE, "", "", - FALSE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + (object_class, PROP_AVAILABLE, + g_param_spec_boolean (NM_FIREWALL_MANAGER_AVAILABLE, "", "", + FALSE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); signals[STARTED] = - g_signal_new ("started", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMFirewallManagerClass, started), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new ("started", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMFirewallManagerClass, started), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } diff --git a/src/nm-firewall-manager.h b/src/nm-firewall-manager.h index 84cb5498..dfa83b45 100644 --- a/src/nm-firewall-manager.h +++ b/src/nm-firewall-manager.h @@ -21,7 +21,7 @@ #ifndef __NETWORKMANAGER_FIREWALL_MANAGER_H__ #define __NETWORKMANAGER_FIREWALL_MANAGER_H__ -#include +#include "nm-default.h" #define FIREWALL_DBUS_SERVICE "org.fedoraproject.FirewallD1" #define FIREWALL_DBUS_PATH "/org/fedoraproject/FirewallD1" @@ -40,8 +40,8 @@ G_BEGIN_DECLS #define NM_FIREWALL_MANAGER_AVAILABLE "available" -struct _NMFirewallPendingCall; -typedef struct _NMFirewallPendingCall *NMFirewallPendingCall; +struct _NMFirewallManagerCallId; +typedef struct _NMFirewallManagerCallId *NMFirewallManagerCallId; typedef struct { GObject parent; @@ -58,18 +58,23 @@ GType nm_firewall_manager_get_type (void); NMFirewallManager *nm_firewall_manager_get (void); -typedef void (*FwAddToZoneFunc) (GError *error, gpointer user_data); - -NMFirewallPendingCall nm_firewall_manager_add_or_change_zone (NMFirewallManager *mgr, +typedef void (*NMFirewallManagerAddRemoveCallback) (NMFirewallManager *self, + NMFirewallManagerCallId call_id, + GError *error, + gpointer user_data); + +NMFirewallManagerCallId nm_firewall_manager_add_or_change_zone (NMFirewallManager *mgr, + const char *iface, + const char *zone, + gboolean add, + NMFirewallManagerAddRemoveCallback callback, + gpointer user_data); +NMFirewallManagerCallId nm_firewall_manager_remove_from_zone (NMFirewallManager *mgr, const char *iface, const char *zone, - gboolean add, - FwAddToZoneFunc callback, + NMFirewallManagerAddRemoveCallback callback, gpointer user_data); -NMFirewallPendingCall nm_firewall_manager_remove_from_zone (NMFirewallManager *mgr, - const char *iface, - const char *zone); -void nm_firewall_manager_cancel_call (NMFirewallManager *mgr, NMFirewallPendingCall fw_call); +void nm_firewall_manager_cancel_call (NMFirewallManagerCallId fw_call); #endif /* __NETWORKMANAGER_FIREWALL_MANAGER_H__ */ diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c index 25bde8ed..069a68f8 100644 --- a/src/nm-iface-helper.c +++ b/src/nm-iface-helper.c @@ -20,7 +20,6 @@ #include "config.h" -#include #include #include #include @@ -28,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -38,15 +36,15 @@ * Forward declare if_nametoindex. */ extern unsigned int if_nametoindex (const char *__ifname); -#include "gsystem-local-alloc.h" +#include "nm-default.h" #include "NetworkManagerUtils.h" #include "nm-linux-platform.h" #include "nm-dhcp-manager.h" -#include "nm-logging.h" #include "main-utils.h" #include "nm-rdisc.h" #include "nm-lndp-rdisc.h" #include "nm-utils.h" +#include "nm-setting-ip6-config.h" #if !defined(NM_DIST_VERSION) # define NM_DIST_VERSION VERSION @@ -71,7 +69,10 @@ static struct { char *dhcp4_address; char *dhcp4_clientid; char *dhcp4_hostname; + char *dhcp4_fqdn; char *iid_str; + NMSettingIP6ConfigAddrGenMode addr_gen_mode; + char *logging_backend; char *opt_log_level; char *opt_log_domains; guint32 priority_v4; @@ -110,7 +111,7 @@ dhcp4_state_changed (NMDhcpClient *client, if (last_config) g_object_unref (last_config); - last_config = nm_ip4_config_new (); + last_config = nm_ip4_config_new (nm_dhcp_client_get_ifindex (client)); nm_ip4_config_replace (last_config, ip4_config, NULL); break; case NM_DHCP_STATE_TIMEOUT: @@ -139,14 +140,13 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da if (system_support == -1) { /* - * Check, if both libnl and the kernel are recent enough, - * to help user space handling RA. If it's not supported, - * we have no ipv6-privacy and must add autoconf addresses - * as /128. The reason for the /128 is to prevent the kernel + * Check, whether kernel is recent enough, to help user space handling RA. + * If it's not supported, we have no ipv6-privacy and must add autoconf + * addresses as /128. + * The reason for the /128 is to prevent the kernel * from adding a prefix route for this address. **/ - system_support = nm_platform_check_support_libnl_extended_ifa_flags () && - nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET); + system_support = nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET); } if (system_support) @@ -158,7 +158,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da ifa_flags |= IFA_F_MANAGETEMPADDR; } - ip6_config = nm_ip6_config_new (); + ip6_config = nm_ip6_config_new (ifindex); if (changed & NM_RDISC_CONFIG_GATEWAYS) { /* Use the first gateway as ordered in router discovery cache. */ @@ -247,7 +247,7 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da if (last_config) g_object_unref (last_config); - last_config = nm_ip6_config_new (); + last_config = nm_ip6_config_new (ifindex); nm_ip6_config_replace (last_config, ip6_config, NULL); } @@ -292,9 +292,12 @@ do_early_setup (int *argc, char **argv[]) { "dhcp4-required", '4', 0, G_OPTION_ARG_NONE, &global_opt.dhcp4_required, N_("Whether DHCPv4 must be successful"), NULL }, { "dhcp4-clientid", 'c', 0, G_OPTION_ARG_STRING, &global_opt.dhcp4_clientid, N_("Hex-encoded DHCPv4 client ID"), NULL }, { "dhcp4-hostname", 'h', 0, G_OPTION_ARG_STRING, &global_opt.dhcp4_hostname, N_("Hostname to send to DHCP server"), N_("barbar") }, + { "dhcp4-fqdn", 'F', 0, G_OPTION_ARG_STRING, &global_opt.dhcp4_fqdn, N_("FQDN to send to DHCP server"), N_("host.domain.org") }, { "priority4", '\0', 0, G_OPTION_ARG_INT64, &priority64_v4, N_("Route priority for IPv4"), N_("0") }, { "priority6", '\0', 0, G_OPTION_ARG_INT64, &priority64_v6, N_("Route priority for IPv6"), N_("1024") }, { "iid", 'e', 0, G_OPTION_ARG_STRING, &global_opt.iid_str, N_("Hex-encoded Interface Identifier"), "" }, + { "addr-gen-mode", 'e', 0, G_OPTION_ARG_INT, &global_opt.addr_gen_mode, N_("IPv6 SLAAC address generation mode"), "eui64" }, + { "logging-backend", '\0', 0, G_OPTION_ARG_STRING, &global_opt.logging_backend, N_("The logging backend configuration value. See logging.backend in NetworkManager.conf"), NULL }, /* Logging/debugging */ { "version", 'V', 0, G_OPTION_ARG_NONE, &global_opt.show_version, N_("Print NetworkManager version and exit"), NULL }, @@ -323,6 +326,19 @@ do_early_setup (int *argc, char **argv[]) global_opt.priority_v6 = (guint32) priority64_v6; } +static void +ip6_address_changed (NMPlatform *platform, + NMPObjectType obj_type, + int iface, + NMPlatformIP6Address *addr, + NMPlatformSignalChangeType change_type, + NMRDisc *rdisc) +{ + if ( (change_type == NM_PLATFORM_SIGNAL_CHANGED && addr->flags & IFA_F_DADFAILED) + || (change_type == NM_PLATFORM_SIGNAL_REMOVED && addr->flags & IFA_F_TENTATIVE)) + nm_rdisc_dad_failed (rdisc, &addr->address); +} + int main (int argc, char *argv[]) { @@ -337,9 +353,7 @@ main (int argc, char *argv[]) gconstpointer tmp; gs_free NMUtilsIPv6IfaceId *iid = NULL; -#if !GLIB_CHECK_VERSION (2, 35, 0) - g_type_init (); -#endif + nm_g_type_init (); setpgid (getpid (), getpid ()); @@ -408,7 +422,9 @@ main (int argc, char *argv[]) main_loop = g_main_loop_new (NULL, FALSE); setup_signals (); - nm_logging_syslog_openlog (global_opt.debug); + nm_logging_syslog_openlog (global_opt.logging_backend + ? global_opt.logging_backend + : (global_opt.debug ? "debug" : NULL)); nm_log_info (LOGD_CORE, "nm-iface-helper (version " NM_DIST_VERSION ") is starting..."); @@ -444,6 +460,7 @@ main (int argc, char *argv[]) global_opt.priority_v4, !!global_opt.dhcp4_hostname, global_opt.dhcp4_hostname, + global_opt.dhcp4_fqdn, global_opt.dhcp4_clientid, 45, NULL, @@ -458,7 +475,7 @@ main (int argc, char *argv[]) if (global_opt.slaac) { nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, ifindex, TRUE); - rdisc = nm_lndp_rdisc_new (ifindex, global_opt.ifname); + rdisc = nm_lndp_rdisc_new (ifindex, global_opt.ifname, global_opt.uuid, global_opt.addr_gen_mode, NULL); g_assert (rdisc); if (iid) @@ -469,6 +486,10 @@ main (int argc, char *argv[]) nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_pinfo"), "0"); nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_rtr_pref"), "0"); + g_signal_connect (NM_PLATFORM_GET, + NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, + G_CALLBACK (ip6_address_changed), + rdisc); g_signal_connect (rdisc, NM_RDISC_CONFIG_CHANGED, G_CALLBACK (rdisc_config_changed), @@ -484,8 +505,6 @@ main (int argc, char *argv[]) g_clear_pointer (&hwaddr, g_byte_array_unref); - nm_logging_syslog_closelog (); - if (pidfile && wrote_pidfile) unlink (pidfile); @@ -505,9 +524,9 @@ nm_main_config_reload (int signal) gconstpointer nm_config_get (void); const char *nm_config_get_dhcp_client (gpointer unused); gboolean nm_config_get_configure_and_quit (gpointer unused); -gconstpointer nm_dbus_manager_get (void); -void nm_dbus_manager_register_exported_type (gpointer unused, GType gtype, gconstpointer unused2); -void nm_dbus_manager_register_object (gpointer unused, const char *path, gpointer object); +gconstpointer nm_bus_manager_get (void); +void nm_bus_manager_register_object (gpointer unused, gpointer object); +void nm_bus_manager_unregister_object (gpointer unused, gpointer object); gconstpointer nm_config_get (void) @@ -528,18 +547,18 @@ nm_config_get_configure_and_quit (gpointer unused) } gconstpointer -nm_dbus_manager_get (void) +nm_bus_manager_get (void) { return GUINT_TO_POINTER (1); } void -nm_dbus_manager_register_exported_type (gpointer unused, GType gtype, gconstpointer unused2) +nm_bus_manager_register_object (gpointer unused, gpointer object) { } void -nm_dbus_manager_register_object (gpointer unused, const char *path, gpointer object) +nm_bus_manager_unregister_object (gpointer unused, gpointer object) { } diff --git a/src/nm-ip4-config-glue.h b/src/nm-ip4-config-glue.h deleted file mode 100644 index 9488be9b..00000000 --- a/src/nm-ip4-config-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_ip4_config_MARSHAL_H__ -#define __dbus_glib_marshal_nm_ip4_config_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_ip4_config_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_ip4_config_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_ip4_config_object_info = { 1, - dbus_glib_nm_ip4_config_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.IP4Config\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.IP4Config\0Addresses\0addresses\0read\0org.freedesktop.NetworkManager.IP4Config\0AddressData\0address_data\0read\0org.freedesktop.NetworkManager.IP4Config\0Gateway\0gateway\0read\0org.freedesktop.NetworkManager.IP4Config\0Routes\0routes\0read\0org.freedesktop.NetworkManager.IP4Config\0RouteData\0route_data\0read\0org.freedesktop.NetworkManager.IP4Config\0Nameservers\0nameservers\0read\0org.freedesktop.NetworkManager.IP4Config\0Domains\0domains\0read\0org.freedesktop.NetworkManager.IP4Config\0Searches\0searches\0read\0org.freedesktop.NetworkManager.IP4Config\0WinsServers\0wins_servers\0read\0\0" -}; - diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index f625d350..78e7fb78 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -26,24 +26,22 @@ #include "nm-ip4-config.h" +#include "nm-default.h" #include "nm-utils.h" #include "nm-platform.h" -#include "nm-dbus-manager.h" -#include "nm-dbus-glib-types.h" -#include "nm-ip4-config-glue.h" #include "NetworkManagerUtils.h" #include "nm-core-internal.h" #include "nm-route-manager.h" -#include "gsystem-local-alloc.h" +#include "nm-core-internal.h" #include "nm-macros-internal.h" -G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, G_TYPE_OBJECT) +#include "nmdbus-ip4-config.h" -#define NM_IP4_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IP4_CONFIG, NMIP4ConfigPrivate)) +G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, NM_TYPE_EXPORTED_OBJECT) -typedef struct { - char *path; +#define NM_IP4_CONFIG_GET_PRIVATE(o) ((o)->priv) +typedef struct _NMIP4ConfigPrivate { gboolean never_default; guint32 gateway; gboolean has_gateway; @@ -52,12 +50,14 @@ typedef struct { GArray *nameservers; GPtrArray *domains; GPtrArray *searches; + GPtrArray *dns_options; guint32 mss; GArray *nis; char *nis_domain; GArray *wins; guint32 mtu; NMIPConfigSource mtu_source; + int ifindex; gint64 route_metric; gboolean metered; } NMIP4ConfigPrivate; @@ -68,6 +68,7 @@ G_STATIC_ASSERT (G_MAXUINT >= 0xFFFFFFFF); enum { PROP_0, + PROP_IFINDEX, PROP_ADDRESS_DATA, PROP_ADDRESSES, PROP_ROUTE_DATA, @@ -76,6 +77,7 @@ enum { PROP_NAMESERVERS, PROP_DOMAINS, PROP_SEARCHES, + PROP_DNS_OPTIONS, PROP_WINS_SERVERS, LAST_PROP @@ -83,41 +85,28 @@ enum { static GParamSpec *obj_properties[LAST_PROP] = { NULL, }; #define _NOTIFY(config, prop) G_STMT_START { g_object_notify_by_pspec (G_OBJECT (config), obj_properties[prop]); } G_STMT_END - NMIP4Config * -nm_ip4_config_new (void) +nm_ip4_config_new (int ifindex) { - return (NMIP4Config *) g_object_new (NM_TYPE_IP4_CONFIG, NULL); + g_return_val_if_fail (ifindex >= -1, NULL); + return (NMIP4Config *) g_object_new (NM_TYPE_IP4_CONFIG, + NM_IP4_CONFIG_IFINDEX, ifindex, + NULL); } - -void -nm_ip4_config_export (NMIP4Config *config) +int +nm_ip4_config_get_ifindex (const NMIP4Config *config) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - static guint32 counter = 0; - - if (!priv->path) { - priv->path = g_strdup_printf (NM_DBUS_PATH "/IP4Config/%d", counter++); - nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->path, config); - } + return NM_IP4_CONFIG_GET_PRIVATE (config)->ifindex; } -const char * -nm_ip4_config_get_dbus_path (const NMIP4Config *config) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - - return priv->path; -} +/******************************************************************/ static gboolean -same_prefix (guint32 address1, guint32 address2, int plen) +_ipv4_is_zeronet (in_addr_t network) { - guint32 masked1 = ntohl (address1) >> (32 - plen); - guint32 masked2 = ntohl (address2) >> (32 - plen); - - return masked1 == masked2; + /* Same as ipv4_is_zeronet() from kernel's include/linux/in.h. */ + return (network & htonl(0xff000000)) == htonl(0x00000000); } /******************************************************************/ @@ -133,9 +122,10 @@ same_prefix (guint32 address1, guint32 address2, int plen) */ gboolean nm_ip4_config_capture_resolv_conf (GArray *nameservers, + GPtrArray *dns_options, const char *rc_contents) { - GPtrArray *read_ns; + GPtrArray *read_ns, *read_options; guint i, j; gboolean changed = FALSE; @@ -163,15 +153,34 @@ nm_ip4_config_capture_resolv_conf (GArray *nameservers, changed = TRUE; } } - g_ptr_array_unref (read_ns); + + if (dns_options) { + read_options = nm_utils_read_resolv_conf_dns_options (rc_contents); + if (!read_options) + return changed; + + for (i = 0; i < read_options->len; i++) { + const char *s = g_ptr_array_index (read_options, i); + + if (_nm_utils_dns_option_validate (s, NULL, NULL, FALSE, _nm_utils_dns_option_descs) && + _nm_utils_dns_option_find_idx (dns_options, s) < 0) { + g_ptr_array_add (dns_options, g_strdup (s)); + changed = TRUE; + } + } + g_ptr_array_unref (read_options); + } + return changed; } static gboolean -addresses_are_duplicate (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b, gboolean consider_plen) +addresses_are_duplicate (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b) { - return a->address == b->address && (!consider_plen || a->plen == b->plen); + return a->address == b->address + && a->plen == b->plen + && ((a->peer_address ^ b->peer_address) & nm_utils_ip4_prefix_to_netmask (a->plen)) == 0; } static gboolean @@ -195,7 +204,7 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) if (nm_platform_link_get_master (NM_PLATFORM_GET, ifindex) > 0) return NULL; - config = nm_ip4_config_new (); + config = nm_ip4_config_new (ifindex); priv = NM_IP4_CONFIG_GET_PRIVATE (config); g_array_unref (priv->addresses); @@ -247,7 +256,7 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf) * nameservers from /etc/resolv.conf. */ if (priv->addresses->len && priv->has_gateway && capture_resolv_conf) { - if (nm_ip4_config_capture_resolv_conf (priv->nameservers, NULL)) + if (nm_ip4_config_capture_resolv_conf (priv->nameservers, priv->dns_options, NULL)) _NOTIFY (config, PROP_NAMESERVERS); } @@ -298,7 +307,16 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_fu route.ifindex = ifindex; route.source = NM_IP_CONFIG_SOURCE_KERNEL; - route.network = nm_utils_ip4_address_clear_host_address (addr->address, addr->plen); + + /* The destination network depends on the peer-address. */ + route.network = nm_utils_ip4_address_clear_host_address (addr->peer_address, addr->plen); + + if (_ipv4_is_zeronet (route.network)) { + /* Kernel doesn't add device-routes for destinations that + * start with 0.x.y.z. Skip them. */ + continue; + } + route.plen = addr->plen; route.pref_src = addr->address; route.metric = default_route_metric; @@ -386,6 +404,7 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu memset (&address, 0, sizeof (address)); nm_ip_address_get_address_binary (s_addr, &address.address); + address.peer_address = address.address; address.plen = nm_ip_address_get_prefix (s_addr); address.lifetime = NM_PLATFORM_LIFETIME_PERMANENT; address.preferred = NM_PLATFORM_LIFETIME_PERMANENT; @@ -435,6 +454,12 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu for (i = 0; i < nsearches; i++) nm_ip4_config_add_search (config, nm_setting_ip_config_get_dns_search (setting, i)); + i = 0; + while ((i = nm_setting_ip_config_next_valid_dns_option (setting, i)) >= 0) { + nm_ip4_config_add_dns_option (config, nm_setting_ip_config_get_dns_option (setting, i)); + i++; + } + g_object_thaw_notify (G_OBJECT (config)); } @@ -443,7 +468,7 @@ nm_ip4_config_create_setting (const NMIP4Config *config) { NMSettingIPConfig *s_ip4; guint32 gateway; - guint naddresses, nroutes, nnameservers, nsearches; + guint naddresses, nroutes, nnameservers, nsearches, noptions; const char *method = NULL; int i; gint64 route_metric; @@ -462,6 +487,7 @@ nm_ip4_config_create_setting (const NMIP4Config *config) nroutes = nm_ip4_config_get_num_routes (config); nnameservers = nm_ip4_config_get_num_nameservers (config); nsearches = nm_ip4_config_get_num_searches (config); + noptions = nm_ip4_config_get_num_dns_options (config); route_metric = nm_ip4_config_get_route_metric (config); /* Addresses */ @@ -537,6 +563,12 @@ nm_ip4_config_create_setting (const NMIP4Config *config) nm_setting_ip_config_add_dns_search (s_ip4, search); } + for (i = 0; i < noptions; i++) { + const char *option = nm_ip4_config_get_dns_option (config, i); + + nm_setting_ip_config_add_dns_option (s_ip4, option); + } + return NM_SETTING (s_ip4); } @@ -593,6 +625,12 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFl nm_ip4_config_add_search (dst, nm_ip4_config_get_search (src, i)); } + /* dns options */ + if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { + for (i = 0; i < nm_ip4_config_get_num_dns_options (src); i++) + nm_ip4_config_add_dns_option (dst, nm_ip4_config_get_dns_option (src, i)); + } + /* MSS */ if (nm_ip4_config_get_mss (src)) nm_ip4_config_set_mss (dst, nm_ip4_config_get_mss (src)); @@ -635,8 +673,7 @@ _addresses_get_index (const NMIP4Config *self, const NMPlatformIP4Address *addr) for (i = 0; i < priv->addresses->len; i++) { const NMPlatformIP4Address *a = &g_array_index (priv->addresses, NMPlatformIP4Address, i); - if (addr->address == a->address && - addr->plen == a->plen) + if (addresses_are_duplicate (addr, a)) return (int) i; } return -1; @@ -703,6 +740,21 @@ _searches_get_index (const NMIP4Config *self, const char *search) return -1; } +static int +_dns_options_get_index (const NMIP4Config *self, const char *option) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->dns_options->len; i++) { + const char *s = g_ptr_array_index (priv->dns_options, i); + + if (g_strcmp0 (option, s) == 0) + return (int) i; + } + return -1; +} + static int _nis_servers_get_index (const NMIP4Config *self, guint32 nis_server) { @@ -798,6 +850,13 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) nm_ip4_config_del_search (dst, idx); } + /* dns options */ + for (i = 0; i < nm_ip4_config_get_num_dns_options (src); i++) { + idx = _dns_options_get_index (dst, nm_ip4_config_get_dns_option (src, i)); + if (idx >= 0) + nm_ip4_config_del_dns_option (dst, idx); + } + /* MSS */ if (nm_ip4_config_get_mss (src) == nm_ip4_config_get_mss (dst)) nm_ip4_config_set_mss (dst, 0); @@ -867,6 +926,7 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src) /* ignore domains */ /* ignore dns searches */ + /* ignore dns options */ /* ignore NIS */ /* ignore WINS */ @@ -891,7 +951,7 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src) gboolean nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relevant_changes) { -#ifndef G_DISABLE_ASSERT +#if NM_MORE_ASSERTS gboolean config_equal; #endif gboolean has_minor_changes = FALSE, has_relevant_changes = FALSE, are_equal; @@ -904,7 +964,7 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev g_return_val_if_fail (dst != NULL, FALSE); g_return_val_if_fail (src != dst, FALSE); -#ifndef G_DISABLE_ASSERT +#if NM_MORE_ASSERTS config_equal = nm_ip4_config_equal (dst, src); #endif @@ -913,6 +973,12 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev g_object_freeze_notify (G_OBJECT (dst)); + /* ifindex */ + if (src_priv->ifindex != dst_priv->ifindex) { + dst_priv->ifindex = src_priv->ifindex; + has_minor_changes = TRUE; + } + /* never_default */ if (src_priv->never_default != dst_priv->never_default) { dst_priv->never_default = src_priv->never_default; @@ -942,7 +1008,8 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev if (nm_platform_ip4_address_cmp (src_addr = nm_ip4_config_get_address (src, i), dst_addr = nm_ip4_config_get_address (dst, i))) { are_equal = FALSE; - if (!addresses_are_duplicate (src_addr, dst_addr, TRUE)) { + if ( !addresses_are_duplicate (src_addr, dst_addr) + || src_addr->peer_address != dst_addr->peer_address) { has_relevant_changes = TRUE; break; } @@ -1036,6 +1103,25 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev has_relevant_changes = TRUE; } + /* dns options */ + num = nm_ip4_config_get_num_dns_options (src); + are_equal = num == nm_ip4_config_get_num_dns_options (dst); + if (are_equal) { + for (i = 0; i < num; i++ ) { + if (g_strcmp0 (nm_ip4_config_get_dns_option (src, i), + nm_ip4_config_get_dns_option (dst, i))) { + are_equal = FALSE; + break; + } + } + } + if (!are_equal) { + nm_ip4_config_reset_dns_options (dst); + for (i = 0; i < num; i++) + nm_ip4_config_add_dns_option (dst, nm_ip4_config_get_dns_option (src, i)); + has_relevant_changes = TRUE; + } + /* mss */ if (src_priv->mss != dst_priv->mss) { nm_ip4_config_set_mss (dst, src_priv->mss); @@ -1096,9 +1182,11 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev has_minor_changes = TRUE; } +#if NM_MORE_ASSERTS /* config_equal does not compare *all* the fields, therefore, we might have has_minor_changes * regardless of config_equal. But config_equal must correspond to has_relevant_changes. */ - g_assert (config_equal == !has_relevant_changes); + nm_assert (config_equal == !has_relevant_changes); +#endif g_object_thaw_notify (G_OBJECT (dst)); @@ -1114,17 +1202,20 @@ nm_ip4_config_dump (const NMIP4Config *config, const char *detail) guint32 i, tmp; const char *str; - g_return_if_fail (config != NULL); - g_message ("--------- NMIP4Config %p (%s)", config, detail); - str = nm_ip4_config_get_dbus_path (config); + if (config == NULL) { + g_message (" (null)"); + return; + } + + str = nm_exported_object_get_path (NM_EXPORTED_OBJECT (config)); if (str) g_message (" path: %s", str); /* addresses */ for (i = 0; i < nm_ip4_config_get_num_addresses (config); i++) - g_message (" a: %s", nm_platform_ip4_address_to_string (nm_ip4_config_get_address (config, i))); + g_message (" a: %s", nm_platform_ip4_address_to_string (nm_ip4_config_get_address (config, i), NULL, 0)); /* default gateway */ if (nm_ip4_config_has_gateway (config)) { @@ -1140,7 +1231,7 @@ nm_ip4_config_dump (const NMIP4Config *config, const char *detail) /* routes */ for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) - g_message (" rt: %s", nm_platform_ip4_route_to_string (nm_ip4_config_get_route (config, i))); + g_message (" rt: %s", nm_platform_ip4_route_to_string (nm_ip4_config_get_route (config, i), NULL, 0)); /* domains */ for (i = 0; i < nm_ip4_config_get_num_domains (config); i++) @@ -1150,6 +1241,11 @@ nm_ip4_config_dump (const NMIP4Config *config, const char *detail) for (i = 0; i < nm_ip4_config_get_num_searches (config); i++) g_message (" search: %s", nm_ip4_config_get_search (config, i)); + /* dns options */ + for (i = 0; i < nm_ip4_config_get_num_dns_options (config); i++) + g_message (" dnsopt: %s", nm_ip4_config_get_dns_option (config, i)); + + g_message (" mss: %"G_GUINT32_FORMAT, nm_ip4_config_get_mss (config)); g_message (" mtu: %"G_GUINT32_FORMAT, nm_ip4_config_get_mtu (config)); @@ -1176,12 +1272,22 @@ nm_ip4_config_destination_is_direct (const NMIP4Config *config, guint32 network, { guint naddresses = nm_ip4_config_get_num_addresses (config); int i; + in_addr_t peer_network; for (i = 0; i < naddresses; i++) { const NMPlatformIP4Address *item = nm_ip4_config_get_address (config, i); - if (item->plen <= plen && same_prefix (item->address, network, item->plen)) - return TRUE; + if (item->plen > plen) + continue; + + peer_network = nm_utils_ip4_address_clear_host_address (item->peer_address, item->plen); + if (_ipv4_is_zeronet (peer_network)) + continue; + + if (peer_network != nm_utils_ip4_address_clear_host_address (network, item->plen)) + continue; + + return TRUE; } return FALSE; @@ -1229,6 +1335,16 @@ nm_ip4_config_unset_gateway (NMIP4Config *config) } } +/** + * nm_ip4_config_has_gateway: + * @config: the #NMIP4Config object + * + * NetworkManager's handling of default-routes is limited and usually a default-route + * cannot have gateway 0.0.0.0. For peer-to-peer routes, we still want to + * support that, so we need to differenciate between no-default-route and a + * on-link-default route. Hence nm_ip4_config_has_gateway(). + * + * Returns: whether the object has a gateway explicitly set. */ gboolean nm_ip4_config_has_gateway (const NMIP4Config *config) { @@ -1289,7 +1405,7 @@ nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *new) for (i = 0; i < priv->addresses->len; i++ ) { NMPlatformIP4Address *item = &g_array_index (priv->addresses, NMPlatformIP4Address, i); - if (addresses_are_duplicate (item, new, FALSE)) { + if (addresses_are_duplicate (item, new)) { if (nm_platform_ip4_address_cmp (item, new) == 0) return; @@ -1356,16 +1472,7 @@ gboolean nm_ip4_config_address_exists (const NMIP4Config *config, const NMPlatformIP4Address *needle) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - guint i; - - for (i = 0; i < priv->addresses->len; i++) { - const NMPlatformIP4Address *haystack = &g_array_index (priv->addresses, NMPlatformIP4Address, i); - - if (needle->address == haystack->address && needle->plen == haystack->plen) - return TRUE; - } - return FALSE; + return _addresses_get_index (config, needle) >= 0; } /******************************************************************/ @@ -1401,6 +1508,7 @@ nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *new) g_return_if_fail (new != NULL); g_return_if_fail (new->plen > 0); + g_assert (priv->ifindex); for (i = 0; i < priv->routes->len; i++ ) { NMPlatformIP4Route *item = &g_array_index (priv->routes, NMPlatformIP4Route, i); @@ -1412,11 +1520,13 @@ nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *new) memcpy (item, new, sizeof (*item)); /* Restore highest priority source */ item->source = MAX (old_source, new->source); + item->ifindex = priv->ifindex; goto NOTIFY; } } g_array_append_val (priv->routes, *new); + g_array_index (priv->routes, NMPlatformIP4Route, priv->routes->len - 1).ifindex = priv->ifindex; NOTIFY: _NOTIFY (config, PROP_ROUTE_DATA); _NOTIFY (config, PROP_ROUTES); @@ -1480,28 +1590,6 @@ nm_ip4_config_get_direct_route_for_host (const NMIP4Config *config, guint32 host return best_route; } -const NMPlatformIP4Address * -nm_ip4_config_get_subnet_for_host (const NMIP4Config *config, guint32 host) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - guint i; - NMPlatformIP4Address *subnet = NULL; - - g_return_val_if_fail (host, NULL); - - for (i = 0; i < priv->addresses->len; i++) { - NMPlatformIP4Address *item = &g_array_index (priv->addresses, NMPlatformIP4Address, i); - - if (subnet && subnet->plen >= item->plen) - continue; - if (nm_utils_ip4_address_clear_host_address (host, item->plen) != nm_utils_ip4_address_clear_host_address (item->address, item->plen)) - continue; - subnet = item; - } - - return subnet; -} - /******************************************************************/ void @@ -1689,6 +1777,63 @@ nm_ip4_config_get_search (const NMIP4Config *config, guint i) /******************************************************************/ +void +nm_ip4_config_reset_dns_options (NMIP4Config *config) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + if (priv->dns_options->len != 0) { + g_ptr_array_set_size (priv->dns_options, 0); + _NOTIFY (config, PROP_DNS_OPTIONS); + } +} + +void +nm_ip4_config_add_dns_option (NMIP4Config *config, const char *new) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + int i; + + g_return_if_fail (new != NULL); + g_return_if_fail (new[0] != '\0'); + + for (i = 0; i < priv->dns_options->len; i++) + if (!g_strcmp0 (g_ptr_array_index (priv->dns_options, i), new)) + return; + + g_ptr_array_add (priv->dns_options, g_strdup (new)); + _NOTIFY (config, PROP_DNS_OPTIONS); +} + +void +nm_ip4_config_del_dns_option(NMIP4Config *config, guint i) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->dns_options->len); + + g_ptr_array_remove_index (priv->dns_options, i); + _NOTIFY (config, PROP_DNS_OPTIONS); +} + +guint32 +nm_ip4_config_get_num_dns_options (const NMIP4Config *config) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + return priv->dns_options->len; +} + +const char * +nm_ip4_config_get_dns_option (const NMIP4Config *config, guint i) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + + return g_ptr_array_index (priv->dns_options, i); +} + +/******************************************************************/ + void nm_ip4_config_set_mss (NMIP4Config *config, guint32 mss) { @@ -1900,6 +2045,7 @@ nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i); hash_u32 (sum, address->address); hash_u32 (sum, address->plen); + hash_u32 (sum, address->peer_address & nm_utils_ip4_prefix_to_netmask (address->plen)); } for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) { @@ -1934,6 +2080,12 @@ nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only s = nm_ip4_config_get_search (config, i); g_checksum_update (sum, (const guint8 *) s, strlen (s)); } + + for (i = 0; i < nm_ip4_config_get_num_dns_options (config); i++) { + s = nm_ip4_config_get_dns_option (config, i); + g_checksum_update (sum, (const guint8 *) s, strlen (s)); + } + } /** @@ -1981,13 +2133,17 @@ nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b) static void nm_ip4_config_init (NMIP4Config *config) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv; + + priv = G_TYPE_INSTANCE_GET_PRIVATE (config, NM_TYPE_IP4_CONFIG, NMIP4ConfigPrivate); + config->priv = priv; priv->addresses = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Address)); priv->routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route)); priv->nameservers = g_array_new (FALSE, FALSE, sizeof (guint32)); priv->domains = g_ptr_array_new_with_free_func (g_free); priv->searches = g_ptr_array_new_with_free_func (g_free); + priv->dns_options = g_ptr_array_new_with_free_func (g_free); priv->nis = g_array_new (FALSE, TRUE, sizeof (guint32)); priv->wins = g_array_new (FALSE, TRUE, sizeof (guint32)); priv->route_metric = -1; @@ -1996,15 +2152,15 @@ nm_ip4_config_init (NMIP4Config *config) static void finalize (GObject *object) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object); - - g_free (priv->path); + NMIP4Config *self = NM_IP4_CONFIG (object); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); g_array_unref (priv->addresses); g_array_unref (priv->routes); g_array_unref (priv->nameservers); g_ptr_array_unref (priv->domains); g_ptr_array_unref (priv->searches); + g_ptr_array_unref (priv->dns_options); g_array_unref (priv->nis); g_free (priv->nis_domain); g_array_unref (priv->wins); @@ -2012,146 +2168,134 @@ finalize (GObject *object) G_OBJECT_CLASS (nm_ip4_config_parent_class)->finalize (object); } -static void -gvalue_destroy (gpointer data) -{ - GValue *value = (GValue *) data; - - g_value_unset (value); - g_slice_free (GValue, value); -} - static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMIP4Config *config = NM_IP4_CONFIG (object); - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (object); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); switch (prop_id) { + case PROP_IFINDEX: + g_value_set_int (value, priv->ifindex); + break; case PROP_ADDRESS_DATA: { - GPtrArray *addresses = g_ptr_array_new (); + GVariantBuilder array_builder, addr_builder; int naddr = nm_ip4_config_get_num_addresses (config); int i; + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); for (i = 0; i < naddr; i++) { const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i); - GHashTable *addr_hash; - GValue *val; - addr_hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gvalue_destroy); - - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_STRING); - g_value_set_string (val, nm_utils_inet4_ntop (address->address, NULL)); - g_hash_table_insert (addr_hash, "address", val); - - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_UINT); - g_value_set_uint (val, address->plen); - g_hash_table_insert (addr_hash, "prefix", val); + g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&addr_builder, "{sv}", + "address", + g_variant_new_string (nm_utils_inet4_ntop (address->address, NULL))); + g_variant_builder_add (&addr_builder, "{sv}", + "prefix", + g_variant_new_uint32 (address->plen)); + if (address->peer_address != address->address) { + g_variant_builder_add (&addr_builder, "{sv}", + "peer", + g_variant_new_string (nm_utils_inet4_ntop (address->peer_address, NULL))); + } if (*address->label) { - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_STRING); - g_value_set_string (val, address->label); - g_hash_table_insert (addr_hash, "label", val); + g_variant_builder_add (&addr_builder, "{sv}", + "label", + g_variant_new_string (address->label)); } - g_ptr_array_add (addresses, addr_hash); + g_variant_builder_add (&array_builder, "a{sv}", &addr_builder); } - g_value_take_boxed (value, addresses); + g_value_take_variant (value, g_variant_builder_end (&array_builder)); } break; case PROP_ADDRESSES: { - GPtrArray *addresses = g_ptr_array_new (); + GVariantBuilder array_builder; int naddr = nm_ip4_config_get_num_addresses (config); int i; + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aau")); for (i = 0; i < naddr; i++) { const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i); - GArray *array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 3); - guint32 gateway = i == 0 ? priv->gateway : 0; + guint32 dbus_addr[3]; - g_array_append_val (array, address->address); - g_array_append_val (array, address->plen); - g_array_append_val (array, gateway); + dbus_addr[0] = address->address; + dbus_addr[1] = address->plen; + dbus_addr[2] = i == 0 ? priv->gateway : 0; - g_ptr_array_add (addresses, array); + g_variant_builder_add (&array_builder, "@au", + g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, + dbus_addr, 3, sizeof (guint32))); } - g_value_take_boxed (value, addresses); + g_value_take_variant (value, g_variant_builder_end (&array_builder)); } break; case PROP_ROUTE_DATA: { - GPtrArray *routes = g_ptr_array_new (); + GVariantBuilder array_builder, route_builder; guint nroutes = nm_ip4_config_get_num_routes (config); int i; + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); for (i = 0; i < nroutes; i++) { const NMPlatformIP4Route *route = nm_ip4_config_get_route (config, i); - GHashTable *route_hash; - GValue *val; - - route_hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gvalue_destroy); - - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_STRING); - g_value_set_string (val, nm_utils_inet4_ntop (route->network, NULL)); - g_hash_table_insert (route_hash, "dest", val); - - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_UINT); - g_value_set_uint (val, route->plen); - g_hash_table_insert (route_hash, "prefix", val); + g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&route_builder, "{sv}", + "dest", + g_variant_new_string (nm_utils_inet4_ntop (route->network, NULL))); + g_variant_builder_add (&route_builder, "{sv}", + "prefix", + g_variant_new_uint32 (route->plen)); if (route->gateway) { - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_STRING); - g_value_set_string (val, nm_utils_inet4_ntop (route->gateway, NULL)); - g_hash_table_insert (route_hash, "next-hop", val); + g_variant_builder_add (&route_builder, "{sv}", + "next-hop", + g_variant_new_string (nm_utils_inet4_ntop (route->gateway, NULL))); } + g_variant_builder_add (&route_builder, "{sv}", + "metric", + g_variant_new_uint32 (route->metric)); - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_UINT); - g_value_set_uint (val, route->metric); - g_hash_table_insert (route_hash, "metric", val); - - g_ptr_array_add (routes, route_hash); + g_variant_builder_add (&array_builder, "a{sv}", &route_builder); } - g_value_take_boxed (value, routes); + g_value_take_variant (value, g_variant_builder_end (&array_builder)); } break; case PROP_ROUTES: { - GPtrArray *routes = g_ptr_array_new (); + GVariantBuilder array_builder; guint nroutes = nm_ip4_config_get_num_routes (config); int i; + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aau")); for (i = 0; i < nroutes; i++) { const NMPlatformIP4Route *route = nm_ip4_config_get_route (config, i); - GArray *array; + guint32 dbus_route[4]; /* legacy versions of nm_ip4_route_set_prefix() in libnm-util assert that the * plen is positive. Skip the default routes not to break older clients. */ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) continue; - array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 4); - g_array_append_val (array, route->network); - g_array_append_val (array, route->plen); - g_array_append_val (array, route->gateway); - g_array_append_val (array, route->metric); + dbus_route[0] = route->network; + dbus_route[1] = route->plen; + dbus_route[2] = route->gateway; + dbus_route[3] = route->metric; - g_ptr_array_add (routes, array); + g_variant_builder_add (&array_builder, "@au", + g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, + dbus_route, 4, sizeof (guint32))); } - g_value_take_boxed (value, routes); + g_value_take_variant (value, g_variant_builder_end (&array_builder)); } break; case PROP_GATEWAY: @@ -2161,16 +2305,46 @@ get_property (GObject *object, guint prop_id, g_value_set_string (value, NULL); break; case PROP_NAMESERVERS: - g_value_set_boxed (value, priv->nameservers); + g_value_take_variant (value, + g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, + priv->nameservers->data, + priv->nameservers->len, + sizeof (guint32))); break; case PROP_DOMAINS: - g_value_set_boxed (value, priv->domains); + nm_utils_g_value_set_strv (value, priv->domains); break; case PROP_SEARCHES: - g_value_set_boxed (value, priv->searches); + nm_utils_g_value_set_strv (value, priv->searches); + break; + case PROP_DNS_OPTIONS: + nm_utils_g_value_set_strv (value, priv->dns_options); break; case PROP_WINS_SERVERS: - g_value_set_boxed (value, priv->wins); + g_value_take_variant (value, + g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, + priv->wins->data, + priv->wins->len, + sizeof (guint32))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NMIP4Config *self = NM_IP4_CONFIG (object); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + + switch (prop_id) { + case PROP_IFINDEX: + priv->ifindex = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -2182,61 +2356,83 @@ static void nm_ip4_config_class_init (NMIP4ConfigClass *config_class) { GObjectClass *object_class = G_OBJECT_CLASS (config_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (config_class); g_type_class_add_private (config_class, sizeof (NMIP4ConfigPrivate)); + exported_object_class->export_path = NM_DBUS_PATH "/IP4Config/%u"; + object_class->get_property = get_property; + object_class->set_property = set_property; object_class->finalize = finalize; + obj_properties[PROP_IFINDEX] = + g_param_spec_int (NM_IP4_CONFIG_IFINDEX, "", "", + -1, G_MAXINT, -1, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_ADDRESS_DATA] = - g_param_spec_boxed (NM_IP4_CONFIG_ADDRESS_DATA, "", "", - DBUS_TYPE_NM_IP_ADDRESSES, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + g_param_spec_variant (NM_IP4_CONFIG_ADDRESS_DATA, "", "", + G_VARIANT_TYPE ("aa{sv}"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_ADDRESSES] = - g_param_spec_boxed (NM_IP4_CONFIG_ADDRESSES, "", "", - DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + g_param_spec_variant (NM_IP4_CONFIG_ADDRESSES, "", "", + G_VARIANT_TYPE ("aau"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_ROUTE_DATA] = - g_param_spec_boxed (NM_IP4_CONFIG_ROUTE_DATA, "", "", - DBUS_TYPE_NM_IP_ROUTES, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + g_param_spec_variant (NM_IP4_CONFIG_ROUTE_DATA, "", "", + G_VARIANT_TYPE ("aa{sv}"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_ROUTES] = - g_param_spec_boxed (NM_IP4_CONFIG_ROUTES, "", "", - DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + g_param_spec_variant (NM_IP4_CONFIG_ROUTES, "", "", + G_VARIANT_TYPE ("aau"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_GATEWAY] = g_param_spec_string (NM_IP4_CONFIG_GATEWAY, "", "", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_NAMESERVERS] = - g_param_spec_boxed (NM_IP4_CONFIG_NAMESERVERS, "", "", - DBUS_TYPE_G_UINT_ARRAY, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + g_param_spec_variant (NM_IP4_CONFIG_NAMESERVERS, "", "", + G_VARIANT_TYPE ("au"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_DOMAINS] = - g_param_spec_boxed (NM_IP4_CONFIG_DOMAINS, "", "", - DBUS_TYPE_G_ARRAY_OF_STRING, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + g_param_spec_boxed (NM_IP4_CONFIG_DOMAINS, "", "", + G_TYPE_STRV, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_SEARCHES] = - g_param_spec_boxed (NM_IP4_CONFIG_SEARCHES, "", "", - DBUS_TYPE_G_ARRAY_OF_STRING, + g_param_spec_boxed (NM_IP4_CONFIG_SEARCHES, "", "", + G_TYPE_STRV, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_DNS_OPTIONS] = + g_param_spec_boxed (NM_IP4_CONFIG_DNS_OPTIONS, "", "", + G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_WINS_SERVERS] = - g_param_spec_boxed (NM_IP4_CONFIG_WINS_SERVERS, "", "", - DBUS_TYPE_G_UINT_ARRAY, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + g_param_spec_variant (NM_IP4_CONFIG_WINS_SERVERS, "", "", + G_VARIANT_TYPE ("au"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, obj_properties); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (config_class), - &dbus_glib_nm_ip4_config_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (config_class), + NMDBUS_TYPE_IP4_CONFIG_SKELETON, + NULL); } diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index cb3038aa..514ba802 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -21,9 +21,7 @@ #ifndef __NETWORKMANAGER_IP4_CONFIG_H__ #define __NETWORKMANAGER_IP4_CONFIG_H__ -#include - -#include "nm-types.h" +#include "nm-exported-object.h" #include "nm-setting-ip4-config.h" #define NM_TYPE_IP4_CONFIG (nm_ip4_config_get_type ()) @@ -33,20 +31,30 @@ #define NM_IS_IP4_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_IP4_CONFIG)) #define NM_IP4_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_IP4_CONFIG, NMIP4ConfigClass)) +struct _NMIP4ConfigPrivate; + struct _NMIP4Config { - GObject parent; + NMExportedObject parent; + + /* private */ + struct _NMIP4ConfigPrivate *priv; }; typedef struct { - GObjectClass parent; + NMExportedObjectClass parent; } NMIP4ConfigClass; +/* internal */ +#define NM_IP4_CONFIG_IFINDEX "ifindex" + +/* public*/ #define NM_IP4_CONFIG_ADDRESS_DATA "address-data" #define NM_IP4_CONFIG_ROUTE_DATA "route-data" #define NM_IP4_CONFIG_GATEWAY "gateway" #define NM_IP4_CONFIG_NAMESERVERS "nameservers" #define NM_IP4_CONFIG_DOMAINS "domains" #define NM_IP4_CONFIG_SEARCHES "searches" +#define NM_IP4_CONFIG_DNS_OPTIONS "dns-options" #define NM_IP4_CONFIG_WINS_SERVERS "wins-servers" /* deprecated */ @@ -56,11 +64,9 @@ typedef struct { GType nm_ip4_config_get_type (void); -NMIP4Config * nm_ip4_config_new (void); +NMIP4Config * nm_ip4_config_new (int ifindex); -/* D-Bus integration */ -void nm_ip4_config_export (NMIP4Config *config); -const char * nm_ip4_config_get_dbus_path (const NMIP4Config *config); +int nm_ip4_config_get_ifindex (const NMIP4Config *config); /* Integration with nm-platform and nm-setting */ NMIP4Config *nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf); @@ -101,7 +107,6 @@ guint32 nm_ip4_config_get_num_routes (const NMIP4Config *config); const NMPlatformIP4Route *nm_ip4_config_get_route (const NMIP4Config *config, guint32 i); const NMPlatformIP4Route *nm_ip4_config_get_direct_route_for_host (const NMIP4Config *config, guint32 host); -const NMPlatformIP4Address *nm_ip4_config_get_subnet_for_host (const NMIP4Config *config, guint32 host); /* Nameservers */ void nm_ip4_config_reset_nameservers (NMIP4Config *config); @@ -124,6 +129,13 @@ void nm_ip4_config_del_search (NMIP4Config *config, guint i); guint32 nm_ip4_config_get_num_searches (const NMIP4Config *config); const char * nm_ip4_config_get_search (const NMIP4Config *config, guint i); +/* DNS options */ +void nm_ip4_config_reset_dns_options (NMIP4Config *config); +void nm_ip4_config_add_dns_option (NMIP4Config *config, const char *option); +void nm_ip4_config_del_dns_option (NMIP4Config *config, guint i); +guint32 nm_ip4_config_get_num_dns_options (const NMIP4Config *config); +const char * nm_ip4_config_get_dns_option (const NMIP4Config *config, guint i); + /* MSS */ void nm_ip4_config_set_mss (NMIP4Config *config, guint32 mss); guint32 nm_ip4_config_get_mss (const NMIP4Config *config); @@ -159,7 +171,7 @@ gboolean nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b); /******************************************************/ /* Testing-only functions */ -gboolean nm_ip4_config_capture_resolv_conf (GArray *nameservers, +gboolean nm_ip4_config_capture_resolv_conf (GArray *nameservers, GPtrArray *dns_options, const char *rc_contents); #endif /* __NETWORKMANAGER_IP4_CONFIG_H__ */ diff --git a/src/nm-ip6-config-glue.h b/src/nm-ip6-config-glue.h deleted file mode 100644 index 87836ebb..00000000 --- a/src/nm-ip6-config-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_ip6_config_MARSHAL_H__ -#define __dbus_glib_marshal_nm_ip6_config_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_ip6_config_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_ip6_config_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_ip6_config_object_info = { 1, - dbus_glib_nm_ip6_config_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.IP6Config\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.IP6Config\0Addresses\0addresses\0read\0org.freedesktop.NetworkManager.IP6Config\0AddressData\0address_data\0read\0org.freedesktop.NetworkManager.IP6Config\0Gateway\0gateway\0read\0org.freedesktop.NetworkManager.IP6Config\0Routes\0routes\0read\0org.freedesktop.NetworkManager.IP6Config\0RouteData\0route_data\0read\0org.freedesktop.NetworkManager.IP6Config\0Nameservers\0nameservers\0read\0org.freedesktop.NetworkManager.IP6Config\0Domains\0domains\0read\0org.freedesktop.NetworkManager.IP6Config\0Searches\0searches\0read\0\0" -}; - diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index f68c4339..fd63dcb4 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -24,26 +24,23 @@ #include #include +#include "nm-default.h" #include "nm-ip6-config.h" -#include "nm-glib-compat.h" #include "nm-utils.h" #include "nm-platform.h" -#include "nm-dbus-manager.h" -#include "nm-dbus-glib-types.h" -#include "nm-ip6-config-glue.h" #include "nm-route-manager.h" +#include "nm-core-internal.h" #include "NetworkManagerUtils.h" #include "nm-macros-internal.h" -#include "nm-core-internal.h" -G_DEFINE_TYPE (NMIP6Config, nm_ip6_config, G_TYPE_OBJECT) +#include "nmdbus-ip6-config.h" -#define NM_IP6_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_IP6_CONFIG, NMIP6ConfigPrivate)) +G_DEFINE_TYPE (NMIP6Config, nm_ip6_config, NM_TYPE_EXPORTED_OBJECT) -typedef struct { - char *path; +#define NM_IP6_CONFIG_GET_PRIVATE(o) ((o)->priv) +typedef struct _NMIP6ConfigPrivate { gboolean never_default; struct in6_addr gateway; GArray *addresses; @@ -51,13 +48,16 @@ typedef struct { GArray *nameservers; GPtrArray *domains; GPtrArray *searches; + GPtrArray *dns_options; guint32 mss; + int ifindex; gint64 route_metric; } NMIP6ConfigPrivate; enum { PROP_0, + PROP_IFINDEX, PROP_ADDRESS_DATA, PROP_ADDRESSES, PROP_ROUTE_DATA, @@ -66,6 +66,7 @@ enum { PROP_NAMESERVERS, PROP_DOMAINS, PROP_SEARCHES, + PROP_DNS_OPTIONS, LAST_PROP }; @@ -74,29 +75,18 @@ static GParamSpec *obj_properties[LAST_PROP] = { NULL, }; NMIP6Config * -nm_ip6_config_new (void) -{ - return (NMIP6Config *) g_object_new (NM_TYPE_IP6_CONFIG, NULL); -} - -void -nm_ip6_config_export (NMIP6Config *config) +nm_ip6_config_new (int ifindex) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - static guint32 counter = 0; - - if (!priv->path) { - priv->path = g_strdup_printf (NM_DBUS_PATH "/IP6Config/%d", counter++); - nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->path, config); - } + g_return_val_if_fail (ifindex >= -1, NULL); + return (NMIP6Config *) g_object_new (NM_TYPE_IP6_CONFIG, + NM_IP6_CONFIG_IFINDEX, ifindex, + NULL); } -const char * -nm_ip6_config_get_dbus_path (const NMIP6Config *config) +int +nm_ip6_config_get_ifindex (const NMIP6Config *config) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - - return priv->path; + return NM_IP6_CONFIG_GET_PRIVATE (config)->ifindex; } /******************************************************************/ @@ -130,9 +120,10 @@ same_prefix (const struct in6_addr *address1, const struct in6_addr *address2, i */ gboolean nm_ip6_config_capture_resolv_conf (GArray *nameservers, + GPtrArray *dns_options, const char *rc_contents) { - GPtrArray *read_ns; + GPtrArray *read_ns, *read_options; guint i, j; gboolean changed = FALSE; @@ -162,15 +153,32 @@ nm_ip6_config_capture_resolv_conf (GArray *nameservers, changed = TRUE; } } - g_ptr_array_unref (read_ns); + + if (dns_options) { + read_options = nm_utils_read_resolv_conf_dns_options (rc_contents); + if (!read_options) + return changed; + + for (i = 0; i < read_options->len; i++) { + const char *s = g_ptr_array_index (read_options, i); + + if (_nm_utils_dns_option_validate (s, NULL, NULL, TRUE, _nm_utils_dns_option_descs) && + _nm_utils_dns_option_find_idx (dns_options, s) < 0) { + g_ptr_array_add (dns_options, g_strdup (s)); + changed = TRUE; + } + } + g_ptr_array_unref (read_options); + } + return changed; } static gboolean -addresses_are_duplicate (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b, gboolean consider_plen) +addresses_are_duplicate (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b) { - return IN6_ARE_ADDR_EQUAL (&a->address, &b->address) && (!consider_plen || a->plen == b->plen); + return IN6_ARE_ADDR_EQUAL (&a->address, &b->address); } static gboolean @@ -305,7 +313,7 @@ nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6Co if (nm_platform_link_get_master (NM_PLATFORM_GET, ifindex) > 0) return NULL; - config = nm_ip6_config_new (); + config = nm_ip6_config_new (ifindex); priv = NM_IP6_CONFIG_GET_PRIVATE (config); g_array_unref (priv->addresses); @@ -356,7 +364,9 @@ nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6Co * nameservers from /etc/resolv.conf. */ if (priv->addresses->len && has_gateway && capture_resolv_conf) - notify_nameservers = nm_ip6_config_capture_resolv_conf (priv->nameservers, NULL); + notify_nameservers = nm_ip6_config_capture_resolv_conf (priv->nameservers, + priv->dns_options, + NULL); g_array_sort_with_data (priv->addresses, _addresses_sort_cmp, GINT_TO_POINTER (use_temporary)); @@ -502,6 +512,12 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, gu for (i = 0; i < nsearches; i++) nm_ip6_config_add_search (config, nm_setting_ip_config_get_dns_search (setting, i)); + i = 0; + while ((i = nm_setting_ip_config_next_valid_dns_option (setting, i)) >= 0) { + nm_ip6_config_add_dns_option (config, nm_setting_ip_config_get_dns_option (setting, i)); + i++; + } + g_object_thaw_notify (G_OBJECT (config)); } @@ -510,7 +526,7 @@ nm_ip6_config_create_setting (const NMIP6Config *config) { NMSettingIPConfig *s_ip6; const struct in6_addr *gateway; - guint naddresses, nroutes, nnameservers, nsearches; + guint naddresses, nroutes, nnameservers, nsearches, noptions; const char *method = NULL; int i; gint64 route_metric; @@ -529,6 +545,7 @@ nm_ip6_config_create_setting (const NMIP6Config *config) nroutes = nm_ip6_config_get_num_routes (config); nnameservers = nm_ip6_config_get_num_nameservers (config); nsearches = nm_ip6_config_get_num_searches (config); + noptions = nm_ip6_config_get_num_dns_options (config); route_metric = nm_ip6_config_get_route_metric (config); /* Addresses */ @@ -611,6 +628,12 @@ nm_ip6_config_create_setting (const NMIP6Config *config) nm_setting_ip_config_add_dns_search (s_ip6, search); } + for (i = 0; i < noptions; i++) { + const char *option = nm_ip6_config_get_dns_option (config, i); + + nm_setting_ip_config_add_dns_option (s_ip6, option); + } + return NM_SETTING (s_ip6); } @@ -668,6 +691,12 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl nm_ip6_config_add_search (dst, nm_ip6_config_get_search (src, i)); } + /* dns options */ + if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { + for (i = 0; i < nm_ip6_config_get_num_dns_options (src); i++) + nm_ip6_config_add_dns_option (dst, nm_ip6_config_get_dns_option (src, i)); + } + if (nm_ip6_config_get_mss (src)) nm_ip6_config_set_mss (dst, nm_ip6_config_get_mss (src)); @@ -702,7 +731,7 @@ _addresses_get_index (const NMIP6Config *self, const NMPlatformIP6Address *addr) for (i = 0; i < priv->addresses->len; i++) { const NMPlatformIP6Address *a = &g_array_index (priv->addresses, NMPlatformIP6Address, i); - if (IN6_ARE_ADDR_EQUAL (&addr->address, &a->address)) + if (addresses_are_duplicate (a, addr)) return (int) i; } return -1; @@ -768,6 +797,21 @@ _searches_get_index (const NMIP6Config *self, const char *search) return -1; } +static int +_dns_options_get_index (const NMIP6Config *self, const char *option) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->dns_options->len; i++) { + const char *s = g_ptr_array_index (priv->dns_options, i); + + if (g_strcmp0 (option, s) == 0) + return (int) i; + } + return -1; +} + /*******************************************************************************/ /** @@ -835,6 +879,13 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) nm_ip6_config_del_search (dst, idx); } + /* dns options */ + for (i = 0; i < nm_ip6_config_get_num_dns_options (src); i++) { + idx = _dns_options_get_index (dst, nm_ip6_config_get_dns_option (src, i)); + if (idx >= 0) + nm_ip6_config_del_dns_option (dst, idx); + } + if (nm_ip6_config_get_mss (src) == nm_ip6_config_get_mss (dst)) nm_ip6_config_set_mss (dst, 0); @@ -886,6 +937,7 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) /* ignore domains */ /* ignore dns searches */ + /* ignome dns options */ g_object_thaw_notify (G_OBJECT (dst)); } @@ -907,7 +959,7 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) gboolean nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relevant_changes) { -#ifndef G_DISABLE_ASSERT +#if NM_MORE_ASSERTS gboolean config_equal; #endif gboolean has_minor_changes = FALSE, has_relevant_changes = FALSE, are_equal; @@ -920,7 +972,7 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev g_return_val_if_fail (dst != NULL, FALSE); g_return_val_if_fail (src != dst, FALSE); -#ifndef G_DISABLE_ASSERT +#if NM_MORE_ASSERTS config_equal = nm_ip6_config_equal (dst, src); #endif @@ -929,6 +981,12 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev g_object_freeze_notify (G_OBJECT (dst)); + /* ifindex */ + if (src_priv->ifindex != dst_priv->ifindex) { + dst_priv->ifindex = src_priv->ifindex; + has_minor_changes = TRUE; + } + /* never_default */ if (src_priv->never_default != dst_priv->never_default) { dst_priv->never_default = src_priv->never_default; @@ -954,7 +1012,10 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev if (nm_platform_ip6_address_cmp (src_addr = nm_ip6_config_get_address (src, i), dst_addr = nm_ip6_config_get_address (dst, i))) { are_equal = FALSE; - if (!addresses_are_duplicate (src_addr, dst_addr, TRUE)) { + if ( !addresses_are_duplicate (src_addr, dst_addr) + || src_addr->plen != dst_addr->plen + || !IN6_ARE_ADDR_EQUAL (nm_platform_ip6_address_get_peer (src_addr), + nm_platform_ip6_address_get_peer (dst_addr))) { has_relevant_changes = TRUE; break; } @@ -1049,15 +1110,36 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev has_relevant_changes = TRUE; } + /* dns options */ + num = nm_ip6_config_get_num_dns_options (src); + are_equal = num == nm_ip6_config_get_num_dns_options (dst); + if (are_equal) { + for (i = 0; i < num; i++ ) { + if (g_strcmp0 (nm_ip6_config_get_dns_option (src, i), + nm_ip6_config_get_dns_option (dst, i))) { + are_equal = FALSE; + break; + } + } + } + if (!are_equal) { + nm_ip6_config_reset_dns_options (dst); + for (i = 0; i < num; i++) + nm_ip6_config_add_dns_option (dst, nm_ip6_config_get_dns_option (src, i)); + has_relevant_changes = TRUE; + } + /* mss */ if (src_priv->mss != dst_priv->mss) { nm_ip6_config_set_mss (dst, src_priv->mss); has_minor_changes = TRUE; } +#if NM_MORE_ASSERTS /* config_equal does not compare *all* the fields, therefore, we might have has_minor_changes * regardless of config_equal. But config_equal must correspond to has_relevant_changes. */ - g_assert (config_equal == !has_relevant_changes); + nm_assert (config_equal == !has_relevant_changes); +#endif g_object_thaw_notify (G_OBJECT (dst)); @@ -1078,13 +1160,13 @@ nm_ip6_config_dump (const NMIP6Config *config, const char *detail) g_message ("--------- NMIP6Config %p (%s)", config, detail); - str = nm_ip6_config_get_dbus_path (config); + str = nm_exported_object_get_path (NM_EXPORTED_OBJECT (config)); if (str) g_message (" path: %s", str); /* addresses */ for (i = 0; i < nm_ip6_config_get_num_addresses (config); i++) - g_message (" a: %s", nm_platform_ip6_address_to_string (nm_ip6_config_get_address (config, i))); + g_message (" a: %s", nm_platform_ip6_address_to_string (nm_ip6_config_get_address (config, i), NULL, 0)); /* default gateway */ tmp = nm_ip6_config_get_gateway (config); @@ -1099,7 +1181,7 @@ nm_ip6_config_dump (const NMIP6Config *config, const char *detail) /* routes */ for (i = 0; i < nm_ip6_config_get_num_routes (config); i++) - g_message (" rt: %s", nm_platform_ip6_route_to_string (nm_ip6_config_get_route (config, i))); + g_message (" rt: %s", nm_platform_ip6_route_to_string (nm_ip6_config_get_route (config, i), NULL, 0)); /* domains */ for (i = 0; i < nm_ip6_config_get_num_domains (config); i++) @@ -1109,6 +1191,10 @@ nm_ip6_config_dump (const NMIP6Config *config, const char *detail) for (i = 0; i < nm_ip6_config_get_num_searches (config); i++) g_message (" search: %s", nm_ip6_config_get_search (config, i)); + /* dns options */ + for (i = 0; i < nm_ip6_config_get_num_dns_options (config); i++) + g_message (" dnsopt: %s", nm_ip6_config_get_dns_option (config, i)); + g_message (" mss: %"G_GUINT32_FORMAT, nm_ip6_config_get_mss (config)); g_message (" n-dflt: %d", nm_ip6_config_get_never_default (config)); } @@ -1200,7 +1286,7 @@ nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new) for (i = 0; i < priv->addresses->len; i++ ) { NMPlatformIP6Address *item = &g_array_index (priv->addresses, NMPlatformIP6Address, i); - if (IN6_ARE_ADDR_EQUAL (&item->address, &new->address)) { + if (addresses_are_duplicate (item, new)) { if (nm_platform_ip6_address_cmp (item, new) == 0) return; @@ -1267,17 +1353,7 @@ gboolean nm_ip6_config_address_exists (const NMIP6Config *config, const NMPlatformIP6Address *needle) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - guint i; - - for (i = 0; i < priv->addresses->len; i++) { - const NMPlatformIP6Address *haystack = &g_array_index (priv->addresses, NMPlatformIP6Address, i); - - if ( IN6_ARE_ADDR_EQUAL (&needle->address, &haystack->address) - && needle->plen == haystack->plen) - return TRUE; - } - return FALSE; + return _addresses_get_index (config, needle) >= 0; } /******************************************************************/ @@ -1313,6 +1389,7 @@ nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *new) g_return_if_fail (new != NULL); g_return_if_fail (new->plen > 0); + g_assert (priv->ifindex); for (i = 0; i < priv->routes->len; i++ ) { NMPlatformIP6Route *item = &g_array_index (priv->routes, NMPlatformIP6Route, i); @@ -1324,11 +1401,13 @@ nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *new) *item = *new; /* Restore highest priority source */ item->source = MAX (old_source, new->source); + item->ifindex = priv->ifindex; goto NOTIFY; } } g_array_append_val (priv->routes, *new); + g_array_index (priv->routes, NMPlatformIP6Route, priv->routes->len - 1).ifindex = priv->ifindex; NOTIFY: _NOTIFY (config, PROP_ROUTE_DATA); _NOTIFY (config, PROP_ROUTES); @@ -1611,6 +1690,63 @@ nm_ip6_config_get_search (const NMIP6Config *config, guint i) /******************************************************************/ +void +nm_ip6_config_reset_dns_options (NMIP6Config *config) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + if (priv->dns_options->len != 0) { + g_ptr_array_set_size (priv->dns_options, 0); + _NOTIFY (config, PROP_DNS_OPTIONS); + } +} + +void +nm_ip6_config_add_dns_option (NMIP6Config *config, const char *new) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + int i; + + g_return_if_fail (new != NULL); + g_return_if_fail (new[0] != '\0'); + + for (i = 0; i < priv->dns_options->len; i++) + if (!g_strcmp0 (g_ptr_array_index (priv->dns_options, i), new)) + return; + + g_ptr_array_add (priv->dns_options, g_strdup (new)); + _NOTIFY (config, PROP_DNS_OPTIONS); +} + +void +nm_ip6_config_del_dns_option (NMIP6Config *config, guint i) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + g_return_if_fail (i < priv->dns_options->len); + + g_ptr_array_remove_index (priv->dns_options, i); + _NOTIFY (config, PROP_DNS_OPTIONS); +} + +guint32 +nm_ip6_config_get_num_dns_options (const NMIP6Config *config) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + return priv->dns_options->len; +} + +const char * +nm_ip6_config_get_dns_option (const NMIP6Config *config, guint i) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + return g_ptr_array_index (priv->dns_options, i); +} + +/******************************************************************/ + void nm_ip6_config_set_mss (NMIP6Config *config, guint32 mss) { @@ -1685,6 +1821,12 @@ nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only s = nm_ip6_config_get_search (config, i); g_checksum_update (sum, (const guint8 *) s, strlen (s)); } + + for (i = 0; i < nm_ip6_config_get_num_dns_options (config); i++) { + s = nm_ip6_config_get_dns_option (config, i); + g_checksum_update (sum, (const guint8 *) s, strlen (s)); + } + } /** @@ -1732,28 +1874,32 @@ nm_ip6_config_equal (const NMIP6Config *a, const NMIP6Config *b) static void nm_ip6_config_init (NMIP6Config *config) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv; + + priv = G_TYPE_INSTANCE_GET_PRIVATE (config, NM_TYPE_IP6_CONFIG, NMIP6ConfigPrivate); + config->priv = priv; priv->addresses = g_array_new (FALSE, TRUE, sizeof (NMPlatformIP6Address)); priv->routes = g_array_new (FALSE, TRUE, sizeof (NMPlatformIP6Route)); priv->nameservers = g_array_new (FALSE, TRUE, sizeof (struct in6_addr)); priv->domains = g_ptr_array_new_with_free_func (g_free); priv->searches = g_ptr_array_new_with_free_func (g_free); + priv->dns_options = g_ptr_array_new_with_free_func (g_free); priv->route_metric = -1; } static void finalize (GObject *object) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object); - - g_free (priv->path); + NMIP6Config *self = NM_IP6_CONFIG (object); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); g_array_unref (priv->addresses); g_array_unref (priv->routes); g_array_unref (priv->nameservers); g_ptr_array_unref (priv->domains); g_ptr_array_unref (priv->searches); + g_ptr_array_unref (priv->dns_options); G_OBJECT_CLASS (nm_ip6_config_parent_class)->finalize (object); } @@ -1761,31 +1907,21 @@ finalize (GObject *object) static void nameservers_to_gvalue (GArray *array, GValue *value) { - GPtrArray *dns; + GVariantBuilder builder; guint i = 0; - dns = g_ptr_array_new (); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("aay")); while (array && (i < array->len)) { struct in6_addr *addr; - GByteArray *bytearray; - addr = &g_array_index (array, struct in6_addr, i++); - bytearray = g_byte_array_sized_new (16); - g_byte_array_append (bytearray, (guint8 *) addr->s6_addr, 16); - g_ptr_array_add (dns, bytearray); + addr = &g_array_index (array, struct in6_addr, i++); + g_variant_builder_add (&builder, "@ay", + g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + addr, 16, 1)); } - g_value_take_boxed (value, dns); -} - -static void -gvalue_destroy (gpointer data) -{ - GValue *value = (GValue *) data; - - g_value_unset (value); - g_slice_free (GValue, value); + g_value_take_variant (value, g_variant_builder_end (&builder)); } static void @@ -1793,168 +1929,123 @@ get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMIP6Config *config = NM_IP6_CONFIG (object); - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (object); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); switch (prop_id) { + case PROP_IFINDEX: + g_value_set_int (value, priv->ifindex); + break; case PROP_ADDRESS_DATA: { - GPtrArray *addresses = g_ptr_array_new (); + GVariantBuilder array_builder, addr_builder; int naddr = nm_ip6_config_get_num_addresses (config); int i; + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); for (i = 0; i < naddr; i++) { const NMPlatformIP6Address *address = nm_ip6_config_get_address (config, i); - GHashTable *addr_hash; - GValue *val; - - addr_hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gvalue_destroy); - - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_STRING); - g_value_set_string (val, nm_utils_inet6_ntop (&address->address, NULL)); - g_hash_table_insert (addr_hash, "address", val); - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_UINT); - g_value_set_uint (val, address->plen); - g_hash_table_insert (addr_hash, "prefix", val); + g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&addr_builder, "{sv}", + "address", + g_variant_new_string (nm_utils_inet6_ntop (&address->address, NULL))); + g_variant_builder_add (&addr_builder, "{sv}", + "prefix", + g_variant_new_uint32 (address->plen)); + if ( !IN6_IS_ADDR_UNSPECIFIED (&address->peer_address) + && !IN6_ARE_ADDR_EQUAL (&address->peer_address, &address->address)) { + g_variant_builder_add (&addr_builder, "{sv}", + "peer", + g_variant_new_string (nm_utils_inet6_ntop (&address->peer_address, NULL))); + } - g_ptr_array_add (addresses, addr_hash); + g_variant_builder_add (&array_builder, "a{sv}", &addr_builder); } - g_value_take_boxed (value, addresses); + g_value_take_variant (value, g_variant_builder_end (&array_builder)); } break; case PROP_ADDRESSES: { - GPtrArray *addresses = g_ptr_array_new (); + GVariantBuilder array_builder; const struct in6_addr *gateway = nm_ip6_config_get_gateway (config); int naddr = nm_ip6_config_get_num_addresses (config); int i; + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a(ayuay)")); for (i = 0; i < naddr; i++) { const NMPlatformIP6Address *address = nm_ip6_config_get_address (config, i); - GValueArray *array = g_value_array_new (3); - GValue element = G_VALUE_INIT; - GByteArray *ba; - - /* IP address */ - g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY); - ba = g_byte_array_new (); - g_byte_array_append (ba, (guint8 *) &address->address, 16); - g_value_take_boxed (&element, ba); - g_value_array_append (array, &element); - g_value_unset (&element); - - /* Prefix */ - g_value_init (&element, G_TYPE_UINT); - g_value_set_uint (&element, address->plen); - g_value_array_append (array, &element); - g_value_unset (&element); - - /* Gateway */ - g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY); - ba = g_byte_array_new (); - g_byte_array_append (ba, (guint8 *) (i == 0 && gateway ? gateway : &in6addr_any), sizeof (*gateway)); - g_value_take_boxed (&element, ba); - g_value_array_append (array, &element); - g_value_unset (&element); - - g_ptr_array_add (addresses, array); + g_variant_builder_add (&array_builder, "(@ayu@ay)", + g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + &address->address, 16, 1), + address->plen, + g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + (i == 0 && gateway ? gateway : &in6addr_any), + 16, 1)); } - g_value_take_boxed (value, addresses); + g_value_take_variant (value, g_variant_builder_end (&array_builder)); } break; case PROP_ROUTE_DATA: { - GPtrArray *routes = g_ptr_array_new (); + GVariantBuilder array_builder, route_builder; guint nroutes = nm_ip6_config_get_num_routes (config); int i; + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); for (i = 0; i < nroutes; i++) { const NMPlatformIP6Route *route = nm_ip6_config_get_route (config, i); - GHashTable *route_hash; - GValue *val; - - route_hash = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, gvalue_destroy); - - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_STRING); - g_value_set_string (val, nm_utils_inet6_ntop (&route->network, NULL)); - g_hash_table_insert (route_hash, "dest", val); - - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_UINT); - g_value_set_uint (val, route->plen); - g_hash_table_insert (route_hash, "prefix", val); + g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&route_builder, "{sv}", + "dest", + g_variant_new_string (nm_utils_inet6_ntop (&route->network, NULL))); + g_variant_builder_add (&route_builder, "{sv}", + "prefix", + g_variant_new_uint32 (route->plen)); if (!IN6_IS_ADDR_UNSPECIFIED (&route->gateway)) { - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_STRING); - g_value_set_string (val, nm_utils_inet6_ntop (&route->gateway, NULL)); - g_hash_table_insert (route_hash, "next-hop", val); + g_variant_builder_add (&route_builder, "{sv}", + "next-hop", + g_variant_new_string (nm_utils_inet6_ntop (&route->gateway, NULL))); } - val = g_slice_new0 (GValue); - g_value_init (val, G_TYPE_UINT); - g_value_set_uint (val, route->metric); - g_hash_table_insert (route_hash, "metric", val); + g_variant_builder_add (&route_builder, "{sv}", + "metric", + g_variant_new_uint32 (route->metric)); - g_ptr_array_add (routes, route_hash); + g_variant_builder_add (&array_builder, "a{sv}", &route_builder); } - g_value_take_boxed (value, routes); + g_value_take_variant (value, g_variant_builder_end (&array_builder)); } break; case PROP_ROUTES: { - GPtrArray *routes = g_ptr_array_new (); + GVariantBuilder array_builder; int nroutes = nm_ip6_config_get_num_routes (config); int i; + g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a(ayuayu)")); for (i = 0; i < nroutes; i++) { - GValueArray *array; const NMPlatformIP6Route *route = nm_ip6_config_get_route (config, i); - GByteArray *ba; - GValue element = G_VALUE_INIT; /* legacy versions of nm_ip6_route_set_prefix() in libnm-util assert that the * plen is positive. Skip the default routes not to break older clients. */ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) continue; - array = g_value_array_new (4); - - g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY); - ba = g_byte_array_new (); - g_byte_array_append (ba, (guint8 *) &route->network, sizeof (route->network)); - g_value_take_boxed (&element, ba); - g_value_array_append (array, &element); - g_value_unset (&element); - - g_value_init (&element, G_TYPE_UINT); - g_value_set_uint (&element, route->plen); - g_value_array_append (array, &element); - g_value_unset (&element); - - g_value_init (&element, DBUS_TYPE_G_UCHAR_ARRAY); - ba = g_byte_array_new (); - g_byte_array_append (ba, (guint8 *) &route->gateway, sizeof (route->gateway)); - g_value_take_boxed (&element, ba); - g_value_array_append (array, &element); - g_value_unset (&element); - - g_value_init (&element, G_TYPE_UINT); - g_value_set_uint (&element, route->metric); - g_value_array_append (array, &element); - g_value_unset (&element); - - g_ptr_array_add (routes, array); + g_variant_builder_add (&array_builder, "(@ayu@ayu)", + g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + &route->network, 16, 1), + (guint32) route->plen, + g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + &route->gateway, 16, 1), + (guint32) route->metric); } - g_value_take_boxed (value, routes); + g_value_take_variant (value, g_variant_builder_end (&array_builder)); } break; case PROP_GATEWAY: @@ -1967,10 +2058,32 @@ get_property (GObject *object, guint prop_id, nameservers_to_gvalue (priv->nameservers, value); break; case PROP_DOMAINS: - g_value_set_boxed (value, priv->domains); + nm_utils_g_value_set_strv (value, priv->domains); break; case PROP_SEARCHES: - g_value_set_boxed (value, priv->searches); + nm_utils_g_value_set_strv (value, priv->searches); + break; + case PROP_DNS_OPTIONS: + nm_utils_g_value_set_strv (value, priv->dns_options); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + NMIP6Config *config = NM_IP6_CONFIG (object); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + + switch (prop_id) { + case PROP_IFINDEX: + priv->ifindex = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1982,58 +2095,78 @@ static void nm_ip6_config_class_init (NMIP6ConfigClass *config_class) { GObjectClass *object_class = G_OBJECT_CLASS (config_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (config_class); g_type_class_add_private (config_class, sizeof (NMIP6ConfigPrivate)); + exported_object_class->export_path = NM_DBUS_PATH "/IP6Config/%u"; + /* virtual methods */ object_class->get_property = get_property; + object_class->set_property = set_property; object_class->finalize = finalize; /* properties */ + obj_properties[PROP_IFINDEX] = + g_param_spec_int (NM_IP6_CONFIG_IFINDEX, "", "", + -1, G_MAXINT, -1, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_ADDRESS_DATA] = - g_param_spec_boxed (NM_IP6_CONFIG_ADDRESS_DATA, "", "", - DBUS_TYPE_NM_IP_ADDRESSES, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + g_param_spec_variant (NM_IP6_CONFIG_ADDRESS_DATA, "", "", + G_VARIANT_TYPE ("aa{sv}"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_ADDRESSES] = - g_param_spec_boxed (NM_IP6_CONFIG_ADDRESSES, "", "", - DBUS_TYPE_G_ARRAY_OF_IP6_ADDRESS, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + g_param_spec_variant (NM_IP6_CONFIG_ADDRESSES, "", "", + G_VARIANT_TYPE ("a(ayuay)"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_ROUTE_DATA] = - g_param_spec_boxed (NM_IP6_CONFIG_ROUTE_DATA, "", "", - DBUS_TYPE_NM_IP_ROUTES, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + g_param_spec_variant (NM_IP6_CONFIG_ROUTE_DATA, "", "", + G_VARIANT_TYPE ("aa{sv}"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_ROUTES] = - g_param_spec_boxed (NM_IP6_CONFIG_ROUTES, "", "", - DBUS_TYPE_G_ARRAY_OF_IP6_ROUTE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + g_param_spec_variant (NM_IP6_CONFIG_ROUTES, "", "", + G_VARIANT_TYPE ("a(ayuayu)"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_GATEWAY] = g_param_spec_string (NM_IP6_CONFIG_GATEWAY, "", "", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_NAMESERVERS] = - g_param_spec_boxed (NM_IP6_CONFIG_NAMESERVERS, "", "", - DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UCHAR, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + g_param_spec_variant (NM_IP6_CONFIG_NAMESERVERS, "", "", + G_VARIANT_TYPE ("aay"), + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_DOMAINS] = - g_param_spec_boxed (NM_IP6_CONFIG_DOMAINS, "", "", - DBUS_TYPE_G_ARRAY_OF_STRING, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + g_param_spec_boxed (NM_IP6_CONFIG_DOMAINS, "", "", + G_TYPE_STRV, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_SEARCHES] = - g_param_spec_boxed (NM_IP6_CONFIG_SEARCHES, "", "", - DBUS_TYPE_G_ARRAY_OF_STRING, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); + g_param_spec_boxed (NM_IP6_CONFIG_SEARCHES, "", "", + G_TYPE_STRV, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); + obj_properties[PROP_DNS_OPTIONS] = + g_param_spec_boxed (NM_IP6_CONFIG_DNS_OPTIONS, "", "", + G_TYPE_STRV, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, LAST_PROP, obj_properties); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (config_class), - &dbus_glib_nm_ip6_config_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (config_class), + NMDBUS_TYPE_IP6_CONFIG_SKELETON, + NULL); } diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 279f89a7..3ee83701 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -21,10 +21,9 @@ #ifndef __NETWORKMANAGER_IP6_CONFIG_H__ #define __NETWORKMANAGER_IP6_CONFIG_H__ -#include #include -#include "nm-types.h" +#include "nm-exported-object.h" #include "nm-setting-ip6-config.h" #define NM_TYPE_IP6_CONFIG (nm_ip6_config_get_type ()) @@ -34,20 +33,30 @@ #define NM_IS_IP6_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_IP6_CONFIG)) #define NM_IP6_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_IP6_CONFIG, NMIP6ConfigClass)) +struct _NMIP6ConfigPrivate; + struct _NMIP6Config { - GObject parent; + NMExportedObject parent; + + /* private */ + struct _NMIP6ConfigPrivate *priv; }; typedef struct { - GObjectClass parent; + NMExportedObjectClass parent; } NMIP6ConfigClass; +/* internal */ +#define NM_IP6_CONFIG_IFINDEX "ifindex" + +/* public */ #define NM_IP6_CONFIG_ADDRESS_DATA "address-data" #define NM_IP6_CONFIG_ROUTE_DATA "route-data" #define NM_IP6_CONFIG_GATEWAY "gateway" #define NM_IP6_CONFIG_NAMESERVERS "nameservers" #define NM_IP6_CONFIG_DOMAINS "domains" #define NM_IP6_CONFIG_SEARCHES "searches" +#define NM_IP6_CONFIG_DNS_OPTIONS "dns-options" /* deprecated */ #define NM_IP6_CONFIG_ADDRESSES "addresses" @@ -56,11 +65,9 @@ typedef struct { GType nm_ip6_config_get_type (void); -NMIP6Config * nm_ip6_config_new (void); +NMIP6Config * nm_ip6_config_new (int ifindex); -/* D-Bus integration */ -void nm_ip6_config_export (NMIP6Config *config); -const char * nm_ip6_config_get_dbus_path (const NMIP6Config *config); +int nm_ip6_config_get_ifindex (const NMIP6Config *config); /* Integration with nm-platform and nm-setting */ NMIP6Config *nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary); @@ -124,6 +131,13 @@ void nm_ip6_config_del_search (NMIP6Config *config, guint i); guint32 nm_ip6_config_get_num_searches (const NMIP6Config *config); const char * nm_ip6_config_get_search (const NMIP6Config *config, guint i); +/* DNS options */ +void nm_ip6_config_reset_dns_options (NMIP6Config *config); +void nm_ip6_config_add_dns_option (NMIP6Config *config, const char *option); +void nm_ip6_config_del_dns_option (NMIP6Config *config, guint i); +guint32 nm_ip6_config_get_num_dns_options (const NMIP6Config *config); +const char * nm_ip6_config_get_dns_option (const NMIP6Config *config, guint i); + /* MSS */ void nm_ip6_config_set_mss (NMIP6Config *config, guint32 mss); guint32 nm_ip6_config_get_mss (const NMIP6Config *config); @@ -135,6 +149,7 @@ gboolean nm_ip6_config_equal (const NMIP6Config *a, const NMIP6Config *b); /* Testing-only functions */ gboolean nm_ip6_config_capture_resolv_conf (GArray *nameservers, + GPtrArray *dns_options, const char *rc_contents); #endif /* __NETWORKMANAGER_IP6_CONFIG_H__ */ diff --git a/src/nm-logging.c b/src/nm-logging.c index b8433a25..60ccb5cb 100644 --- a/src/nm-logging.c +++ b/src/nm-logging.c @@ -32,11 +32,15 @@ #include #include -#include +#if SYSTEMD_JOURNAL +#define SD_JOURNAL_SUPPRESS_LOCATION +#include +#endif -#include "nm-glib-compat.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-errors.h" +#include "NetworkManagerUtils.h" +#include "nm-linux-platform.h" static void nm_log_handler (const gchar *log_domain, @@ -44,65 +48,91 @@ nm_log_handler (const gchar *log_domain, const gchar *message, gpointer ignored); -static NMLogLevel log_level = LOGL_INFO; -static char *log_domains; -static NMLogDomain logging[LOGL_MAX]; -static gboolean logging_set_up; -static gboolean syslog_opened; -static char *logging_domains_to_string; - typedef struct { NMLogDomain num; const char *name; } LogDesc; -static const char *level_names[LOGL_MAX] = { - [LOGL_TRACE] = "TRACE", - [LOGL_DEBUG] = "DEBUG", - [LOGL_INFO] = "INFO", - [LOGL_WARN] = "WARN", - [LOGL_ERR] = "ERR", +typedef struct { + const char *name; + const char *level_str; + int syslog_level; + GLogLevelFlags g_log_level; + gboolean full_details; +} LogLevelDesc; + +static struct { + NMLogLevel log_level; + NMLogDomain logging[_LOGL_N_REAL]; + gboolean logging_set_up; + enum { + LOG_BACKEND_GLIB, + LOG_BACKEND_SYSLOG, + LOG_BACKEND_JOURNAL, + LOG_BACKEND_JOURNAL_SYSLOG_STYLE, + } log_backend; + char *logging_domains_to_string; + const LogLevelDesc level_desc[_LOGL_N]; + +#define _DOMAIN_DESC_LEN 36 + /* Would be nice to use C99 flexible array member here, + * but that feature doesn't seem well supported. */ + const LogDesc domain_desc[_DOMAIN_DESC_LEN]; +} global = { + .log_level = LOGL_INFO, + .log_backend = LOG_BACKEND_GLIB, + .level_desc = { + [LOGL_TRACE] = { "TRACE", "", LOG_DEBUG, G_LOG_LEVEL_DEBUG, TRUE }, + [LOGL_DEBUG] = { "DEBUG", "", LOG_INFO, G_LOG_LEVEL_DEBUG, TRUE }, + [LOGL_INFO] = { "INFO", "", LOG_INFO, G_LOG_LEVEL_MESSAGE, FALSE }, + [LOGL_WARN] = { "WARN", "", LOG_WARNING, G_LOG_LEVEL_WARNING, FALSE }, + [LOGL_ERR] = { "ERR", "", LOG_ERR, G_LOG_LEVEL_WARNING, TRUE }, + [_LOGL_OFF] = { "OFF", NULL, 0, 0, FALSE }, + [_LOGL_KEEP] = { "KEEP", NULL, 0, 0, FALSE }, + }, + .domain_desc = { + { LOGD_PLATFORM, "PLATFORM" }, + { LOGD_RFKILL, "RFKILL" }, + { LOGD_ETHER, "ETHER" }, + { LOGD_WIFI, "WIFI" }, + { LOGD_BT, "BT" }, + { LOGD_MB, "MB" }, + { LOGD_DHCP4, "DHCP4" }, + { LOGD_DHCP6, "DHCP6" }, + { LOGD_PPP, "PPP" }, + { LOGD_WIFI_SCAN, "WIFI_SCAN" }, + { LOGD_IP4, "IP4" }, + { LOGD_IP6, "IP6" }, + { LOGD_AUTOIP4, "AUTOIP4" }, + { LOGD_DNS, "DNS" }, + { LOGD_VPN, "VPN" }, + { LOGD_SHARING, "SHARING" }, + { LOGD_SUPPLICANT,"SUPPLICANT" }, + { LOGD_AGENTS, "AGENTS" }, + { LOGD_SETTINGS, "SETTINGS" }, + { LOGD_SUSPEND, "SUSPEND" }, + { LOGD_CORE, "CORE" }, + { LOGD_DEVICE, "DEVICE" }, + { LOGD_OLPC, "OLPC" }, + { LOGD_INFINIBAND,"INFINIBAND" }, + { LOGD_FIREWALL, "FIREWALL" }, + { LOGD_ADSL, "ADSL" }, + { LOGD_BOND, "BOND" }, + { LOGD_VLAN, "VLAN" }, + { LOGD_BRIDGE, "BRIDGE" }, + { LOGD_DBUS_PROPS,"DBUS_PROPS" }, + { LOGD_TEAM, "TEAM" }, + { LOGD_CONCHECK, "CONCHECK" }, + { LOGD_DCB, "DCB" }, + { LOGD_DISPATCH, "DISPATCH" }, + { LOGD_AUDIT, "AUDIT" }, + { 0, NULL } + /* keep _DOMAIN_DESC_LEN in sync */ + }, }; -static const LogDesc domain_descs[] = { - { LOGD_NONE, "NONE" }, - { LOGD_PLATFORM, "PLATFORM" }, - { LOGD_RFKILL, "RFKILL" }, - { LOGD_ETHER, "ETHER" }, - { LOGD_WIFI, "WIFI" }, - { LOGD_BT, "BT" }, - { LOGD_MB, "MB" }, - { LOGD_DHCP4, "DHCP4" }, - { LOGD_DHCP6, "DHCP6" }, - { LOGD_PPP, "PPP" }, - { LOGD_WIFI_SCAN, "WIFI_SCAN" }, - { LOGD_IP4, "IP4" }, - { LOGD_IP6, "IP6" }, - { LOGD_AUTOIP4, "AUTOIP4" }, - { LOGD_DNS, "DNS" }, - { LOGD_VPN, "VPN" }, - { LOGD_SHARING, "SHARING" }, - { LOGD_SUPPLICANT,"SUPPLICANT" }, - { LOGD_AGENTS, "AGENTS" }, - { LOGD_SETTINGS, "SETTINGS" }, - { LOGD_SUSPEND, "SUSPEND" }, - { LOGD_CORE, "CORE" }, - { LOGD_DEVICE, "DEVICE" }, - { LOGD_OLPC, "OLPC" }, - { LOGD_WIMAX, "WIMAX" }, - { LOGD_INFINIBAND,"INFINIBAND" }, - { LOGD_FIREWALL, "FIREWALL" }, - { LOGD_ADSL, "ADSL" }, - { LOGD_BOND, "BOND" }, - { LOGD_VLAN, "VLAN" }, - { LOGD_BRIDGE, "BRIDGE" }, - { LOGD_DBUS_PROPS,"DBUS_PROPS" }, - { LOGD_TEAM, "TEAM" }, - { LOGD_CONCHECK, "CONCHECK" }, - { LOGD_DCB, "DCB" }, - { LOGD_DISPATCH, "DISPATCH" }, - { 0, NULL } -}; +/* We have more then 32 logging domains. Assert that it compiles to a 64 bit sized enum */ +G_STATIC_ASSERT (sizeof (NMLogDomain) >= sizeof (guint64)); /* Combined domains */ #define LOGD_ALL_STRING "ALL" @@ -112,11 +142,15 @@ static const LogDesc domain_descs[] = { /************************************************************************/ +static char *_domains_to_string (gboolean include_level_override); + +/************************************************************************/ + static void _ensure_initialized (void) { - if (G_UNLIKELY (!logging_set_up)) - nm_logging_setup ("INFO", "DEFAULT", NULL, NULL); + if (G_UNLIKELY (!global.logging_set_up)) + nm_logging_setup ("INFO", LOGD_DEFAULT_STRING, NULL, NULL); } static gboolean @@ -126,8 +160,8 @@ match_log_level (const char *level, { int i; - for (i = 0; i < LOGL_MAX; i++) { - if (!g_ascii_strcasecmp (level_names[i], level)) { + for (i = 0; i < G_N_ELEMENTS (global.level_desc); i++) { + if (!g_ascii_strcasecmp (global.level_desc[i].name, level)) { *out_level = i; return TRUE; } @@ -145,29 +179,39 @@ nm_logging_setup (const char *level, GError **error) { GString *unrecognized = NULL; - NMLogDomain new_logging[LOGL_MAX]; - NMLogLevel new_log_level = log_level; + NMLogDomain new_logging[G_N_ELEMENTS (global.logging)]; + NMLogLevel new_log_level = global.log_level; char **tmp, **iter; int i; + gboolean had_platform_debug; + gs_free char *domains_free = NULL; g_return_val_if_fail (!bad_domains || !*bad_domains, FALSE); g_return_val_if_fail (!error || !*error, FALSE); - logging_set_up = TRUE; + /* domains */ + if (!domains || !*domains) { + domains = global.logging_set_up + ? (domains_free = _domains_to_string (FALSE)) + : LOGD_DEFAULT_STRING; + } - for (i = 0; i < LOGL_MAX; i++) + global.logging_set_up = TRUE; + + for (i = 0; i < G_N_ELEMENTS (new_logging); i++) new_logging[i] = 0; /* levels */ if (level && *level) { if (!match_log_level (level, &new_log_level, error)) return FALSE; + if (new_log_level == _LOGL_KEEP) { + new_log_level = global.log_level; + for (i = 0; i < G_N_ELEMENTS (new_logging); i++) + new_logging[i] = global.logging[i]; + } } - /* domains */ - if (!domains || !*domains) - domains = log_domains ? log_domains : "DEFAULT"; - tmp = g_strsplit_set (domains, ", ", 0); for (iter = tmp; iter && *iter; iter++) { const LogDesc *diter; @@ -203,48 +247,62 @@ nm_logging_setup (const char *level, /* Check for compatibility domains */ else if (!g_ascii_strcasecmp (*iter, "HW")) bits = LOGD_PLATFORM; + else if (!g_ascii_strcasecmp (*iter, "WIMAX")) + continue; else { - for (diter = &domain_descs[0]; diter->name; diter++) { + for (diter = &global.domain_desc[0]; diter->name; diter++) { if (!g_ascii_strcasecmp (diter->name, *iter)) { bits = diter->num; break; } } - } - if (!bits) { - if (!bad_domains) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_LOG_DOMAIN, - _("Unknown log domain '%s'"), *iter); - return FALSE; - } + if (!bits) { + if (!bad_domains) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_LOG_DOMAIN, + _("Unknown log domain '%s'"), *iter); + return FALSE; + } - if (unrecognized) - g_string_append (unrecognized, ", "); - else - unrecognized = g_string_new (NULL); - g_string_append (unrecognized, *iter); - continue; + if (unrecognized) + g_string_append (unrecognized, ", "); + else + unrecognized = g_string_new (NULL); + g_string_append (unrecognized, *iter); + continue; + } } - for (i = 0; i < domain_log_level; i++) - new_logging[i] &= ~bits; - for (i = domain_log_level; i < LOGL_MAX; i++) - new_logging[i] |= bits; + if (domain_log_level == _LOGL_KEEP) { + for (i = 0; i < G_N_ELEMENTS (new_logging); i++) + new_logging[i] = (new_logging[i] & ~bits) | (global.logging[i] & bits); + } else { + for (i = 0; i < G_N_ELEMENTS (new_logging); i++) { + if (i < domain_log_level) + new_logging[i] &= ~bits; + else + new_logging[i] |= bits; + } + } } g_strfreev (tmp); - if (log_domains != (char *)domains) { - g_free (log_domains); - log_domains = g_strdup (domains); - } + g_clear_pointer (&global.logging_domains_to_string, g_free); + + had_platform_debug = nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM); - g_clear_pointer (&logging_domains_to_string, g_free); + global.log_level = new_log_level; + for (i = 0; i < G_N_ELEMENTS (new_logging); i++) + global.logging[i] = new_logging[i]; - log_level = new_log_level; - for (i = 0; i < LOGL_MAX; i++) - logging[i] = new_logging[i]; + if ( had_platform_debug + && !nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) { + /* when debug logging is enabled, platform will cache all access to + * sysctl. When the user disables debug-logging, we want to clear that + * cache right away. */ + _nm_linux_platform_sysctl_clear_cache (); + } if (unrecognized) *bad_domains = g_string_free (unrecognized, FALSE); @@ -255,7 +313,7 @@ nm_logging_setup (const char *level, const char * nm_logging_level_to_string (void) { - return level_names[log_level]; + return global.level_desc[global.log_level].name; } const char * @@ -267,10 +325,10 @@ nm_logging_all_levels_to_string (void) int i; str = g_string_new (NULL); - for (i = 0; i < LOGL_MAX; i++) { + for (i = 0; i < G_N_ELEMENTS (global.level_desc); i++) { if (str->len) g_string_append_c (str, ','); - g_string_append (str, level_names[i]); + g_string_append (str, global.level_desc[i].name); } } @@ -282,45 +340,54 @@ nm_logging_domains_to_string (void) { _ensure_initialized (); - if (G_UNLIKELY (!logging_domains_to_string)) { - const LogDesc *diter; - GString *str; - int i; + if (G_UNLIKELY (!global.logging_domains_to_string)) + global.logging_domains_to_string = _domains_to_string (TRUE); - /* We don't just return g_strdup (log_domains) because we want to expand - * "DEFAULT" and "ALL". - */ + return global.logging_domains_to_string; +} - str = g_string_sized_new (75); - for (diter = &domain_descs[0]; diter->name; diter++) { - /* If it's set for any lower level, it will also be set for LOGL_ERR */ - if (!(diter->num & logging[LOGL_ERR])) - continue; +static char * +_domains_to_string (gboolean include_level_override) +{ + const LogDesc *diter; + GString *str; + int i; - if (str->len) - g_string_append_c (str, ','); - g_string_append (str, diter->name); + /* We don't just return g_strdup (global.log_domains) because we want to expand + * "DEFAULT" and "ALL". + */ - /* Check if it's logging at a lower level than the default. */ - for (i = 0; i < log_level; i++) { - if (diter->num & logging[i]) { - g_string_append_printf (str, ":%s", level_names[i]); - break; - } + str = g_string_sized_new (75); + for (diter = &global.domain_desc[0]; diter->name; diter++) { + /* If it's set for any lower level, it will also be set for LOGL_ERR */ + if (!(diter->num & global.logging[LOGL_ERR])) + continue; + + if (str->len) + g_string_append_c (str, ','); + g_string_append (str, diter->name); + + if (!include_level_override) + continue; + + /* Check if it's logging at a lower level than the default. */ + for (i = 0; i < global.log_level; i++) { + if (diter->num & global.logging[i]) { + g_string_append_printf (str, ":%s", global.level_desc[i].name); + break; } - /* Check if it's logging at a higher level than the default. */ - if (!(diter->num & logging[log_level])) { - for (i = log_level + 1; i < LOGL_MAX; i++) { - if (diter->num & logging[i]) { - g_string_append_printf (str, ":%s", level_names[i]); - break; - } + } + /* Check if it's logging at a higher level than the default. */ + if (!(diter->num & global.logging[global.log_level])) { + for (i = global.log_level + 1; i < G_N_ELEMENTS (global.logging); i++) { + if (diter->num & global.logging[i]) { + g_string_append_printf (str, ":%s", global.level_desc[i].name); + break; } } } - logging_domains_to_string = g_string_free (str, FALSE); } - return logging_domains_to_string; + return g_string_free (str, FALSE); } const char * @@ -332,7 +399,7 @@ nm_logging_all_domains_to_string (void) const LogDesc *diter; str = g_string_new (LOGD_DEFAULT_STRING); - for (diter = &domain_descs[0]; diter->name; diter++) { + for (diter = &global.domain_desc[0]; diter->name; diter++) { g_string_append_c (str, ','); g_string_append (str, diter->name); if (diter->num == LOGD_DHCP6) @@ -349,12 +416,40 @@ nm_logging_all_domains_to_string (void) gboolean nm_logging_enabled (NMLogLevel level, NMLogDomain domain) { - g_return_val_if_fail (level < LOGL_MAX, FALSE); + if ((guint) level >= G_N_ELEMENTS (global.logging)) + g_return_val_if_reached (FALSE); _ensure_initialized (); - return !!(logging[level] & domain); + return !!(global.logging[level] & domain); +} + +#if SYSTEMD_JOURNAL +__attribute__((__format__ (__printf__, 4, 5))) +static void +_iovec_set_format (struct iovec *iov, gboolean *iov_free, int i, const char *format, ...) +{ + va_list ap; + char *str; + + va_start (ap, format); + str = g_strdup_vprintf (format, ap); + va_end (ap); + + iov[i].iov_base = str; + iov[i].iov_len = strlen (str); + iov_free[i] = TRUE; +} + +static void +_iovec_set_string (struct iovec *iov, gboolean *iov_free, int i, const char *str, gsize len) +{ + iov[i].iov_base = (char *) str; + iov[i].iov_len = len; + iov_free[i] = FALSE; } +#define _iovec_set_literal_string(iov, iov_free, i, str) _iovec_set_string ((iov), (iov_free), (i), (""str""), STRLEN (str)) +#endif void _nm_log_impl (const char *file, @@ -370,14 +465,13 @@ _nm_log_impl (const char *file, char *msg; char *fullmsg = NULL; GTimeVal tv; - int syslog_level = LOG_INFO; - int g_log_level = G_LOG_LEVEL_INFO; - g_return_if_fail (level < LOGL_MAX); + if ((guint) level >= G_N_ELEMENTS (global.logging)) + g_return_if_reached (); _ensure_initialized (); - if (!(logging[level] & domain)) + if (!(global.logging[level] & domain)) return; /* Make sure that %m maps to the specified error */ @@ -391,44 +485,106 @@ _nm_log_impl (const char *file, msg = g_strdup_vprintf (fmt, args); va_end (args); - switch (level) { - case LOGL_TRACE: - g_get_current_time (&tv); - syslog_level = LOG_DEBUG; - g_log_level = G_LOG_LEVEL_DEBUG; - fullmsg = g_strdup_printf (" [%ld.%06ld] [%s:%u] %s(): %s", tv.tv_sec, tv.tv_usec, file, line, func, msg); - break; - case LOGL_DEBUG: - g_get_current_time (&tv); - syslog_level = LOG_INFO; - g_log_level = G_LOG_LEVEL_DEBUG; - fullmsg = g_strdup_printf (" [%ld.%06ld] [%s:%u] %s(): %s", tv.tv_sec, tv.tv_usec, file, line, func, msg); - break; - case LOGL_INFO: - syslog_level = LOG_INFO; - g_log_level = G_LOG_LEVEL_MESSAGE; - fullmsg = g_strconcat (" ", msg, NULL); - break; - case LOGL_WARN: - syslog_level = LOG_WARNING; - g_log_level = G_LOG_LEVEL_WARNING; - fullmsg = g_strconcat (" ", msg, NULL); - break; - case LOGL_ERR: - syslog_level = LOG_ERR; - /* g_log_level is still WARNING, because ERROR is fatal */ - g_log_level = G_LOG_LEVEL_WARNING; - g_get_current_time (&tv); - fullmsg = g_strdup_printf (" [%ld.%06ld] [%s:%u] %s(): %s", tv.tv_sec, tv.tv_usec, file, line, func, msg); + switch (global.log_backend) { +#if SYSTEMD_JOURNAL + case LOG_BACKEND_JOURNAL: + case LOG_BACKEND_JOURNAL_SYSLOG_STYLE: + { + gint64 now, boottime; +#define _NUM_MAX_FIELDS_SYSLOG_FACILITY 10 +#define _NUM_FIELDS (10 + _NUM_MAX_FIELDS_SYSLOG_FACILITY) + int i_field = 0; + struct iovec iov[_NUM_FIELDS]; + gboolean iov_free[_NUM_FIELDS]; + + now = nm_utils_get_monotonic_timestamp_ns (); + boottime = nm_utils_monotonic_timestamp_as_boottime (now, 1); + + _iovec_set_format (iov, iov_free, i_field++, "PRIORITY=%d", global.level_desc[level].syslog_level); + if ( global.log_backend == LOG_BACKEND_JOURNAL_SYSLOG_STYLE + && global.level_desc[level].full_details) { + g_get_current_time (&tv); + _iovec_set_format (iov, iov_free, i_field++, "MESSAGE=%-7s [%ld.%06ld] [%s:%u] %s(): %s", global.level_desc[level].level_str, tv.tv_sec, tv.tv_usec, file, line, func, msg); + } else + _iovec_set_format (iov, iov_free, i_field++, "MESSAGE=%-7s %s", global.level_desc[level].level_str, msg); + _iovec_set_literal_string (iov, iov_free, i_field++, "SYSLOG_IDENTIFIER=" G_LOG_DOMAIN); + _iovec_set_format (iov, iov_free, i_field++, "SYSLOG_PID=%ld", (long) getpid ()); + { + const LogDesc *diter; + int i_domain = _NUM_MAX_FIELDS_SYSLOG_FACILITY; + const char *s_domain_1 = NULL; + GString *s_domain_all = NULL; + NMLogDomain dom_all = domain; + NMLogDomain dom = dom_all & global.logging[level]; + + for (diter = &global.domain_desc[0]; diter->name; diter++) { + if (!NM_FLAGS_HAS (dom_all, diter->num)) + continue; + + /* construct a list of all domains (not only the enabled ones). + * Note that in by far most cases, there is only one domain present. + * Hence, save the construction of the GString. */ + dom_all &= ~diter->num; + if (!s_domain_1) + s_domain_1 = diter->name; + else { + if (!s_domain_all) + s_domain_all = g_string_new (s_domain_1); + g_string_append_c (s_domain_all, ','); + g_string_append (s_domain_all, diter->name); + } + + if (NM_FLAGS_HAS (dom, diter->num)) { + if (i_domain > 0) { + /* SYSLOG_FACILITY is specified multiple times for each domain that is actually enabled. */ + _iovec_set_format (iov, iov_free, i_field++, "SYSLOG_FACILITY=%s", diter->name); + i_domain--; + } + dom &= ~diter->num; + } + if (!dom && !dom_all) + break; + } + if (s_domain_all) { + _iovec_set_format (iov, iov_free, i_field++, "NM_LOG_DOMAINS=%s", s_domain_all->str); + g_string_free (s_domain_all, TRUE); + } else + _iovec_set_format (iov, iov_free, i_field++, "NM_LOG_DOMAINS=%s", s_domain_1); + } + _iovec_set_format (iov, iov_free, i_field++, "NM_LOG_LEVEL=%s", global.level_desc[level].name); + _iovec_set_format (iov, iov_free, i_field++, "CODE_FUNC=%s", func); + _iovec_set_format (iov, iov_free, i_field++, "CODE_FILE=%s", file); + _iovec_set_format (iov, iov_free, i_field++, "CODE_LINE=%u", line); + _iovec_set_format (iov, iov_free, i_field++, "TIMESTAMP_MONOTONIC=%lld.%06lld", (long long) (now / NM_UTILS_NS_PER_SECOND), (long long) ((now % NM_UTILS_NS_PER_SECOND) / 1000)); + _iovec_set_format (iov, iov_free, i_field++, "TIMESTAMP_BOOTTIME=%lld.%06lld", (long long) (boottime / NM_UTILS_NS_PER_SECOND), (long long) ((boottime % NM_UTILS_NS_PER_SECOND) / 1000)); + if (error != 0) + _iovec_set_format (iov, iov_free, i_field++, "ERRNO=%d", error); + + nm_assert (i_field <= G_N_ELEMENTS (iov)); + + sd_journal_sendv (iov, i_field); + + for (; i_field > 0; ) { + i_field--; + if (iov_free[i_field]) + g_free (iov[i_field].iov_base); + } + } break; +#endif default: - g_assert_not_reached (); - } + if (global.level_desc[level].full_details) { + g_get_current_time (&tv); + fullmsg = g_strdup_printf ("%-7s [%ld.%06ld] [%s:%u] %s(): %s", global.level_desc[level].level_str, tv.tv_sec, tv.tv_usec, file, line, func, msg); + } else + fullmsg = g_strdup_printf ("%-7s %s", global.level_desc[level].level_str, msg); - if (syslog_opened) - syslog (syslog_level, "%s", fullmsg); - else - g_log (G_LOG_DOMAIN, g_log_level, "%s", fullmsg); + if (global.log_backend == LOG_BACKEND_SYSLOG) + syslog (global.level_desc[level].syslog_level, "%s", fullmsg); + else + g_log (G_LOG_DOMAIN, global.level_desc[level].g_log_level, "%s", fullmsg); + break; + } g_free (msg); g_free (fullmsg); @@ -442,7 +598,7 @@ nm_log_handler (const gchar *log_domain, const gchar *message, gpointer ignored) { - int syslog_priority; + int syslog_priority; switch (level & G_LOG_LEVEL_MASK) { case G_LOG_LEVEL_ERROR: @@ -466,30 +622,66 @@ nm_log_handler (const gchar *log_domain, break; } - syslog (syslog_priority, "%s", message); + switch (global.log_backend) { +#if SYSTEMD_JOURNAL + case LOG_BACKEND_JOURNAL: + case LOG_BACKEND_JOURNAL_SYSLOG_STYLE: + { + gint64 now, boottime; + + now = nm_utils_get_monotonic_timestamp_ns (); + boottime = nm_utils_monotonic_timestamp_as_boottime (now, 1); + + sd_journal_send ("PRIORITY=%d", syslog_priority, + "MESSAGE=%s", str_if_set (message, ""), + "SYSLOG_IDENTIFIER=%s", G_LOG_DOMAIN, + "SYSLOG_PID=%ld", (long) getpid (), + "SYSLOG_FACILITY=GLIB", + "GLIB_DOMAIN=%s", str_if_set (log_domain, ""), + "GLIB_LEVEL=%d", (int) (level & G_LOG_LEVEL_MASK), + "TIMESTAMP_MONOTONIC=%lld.%06lld", (long long) (now / NM_UTILS_NS_PER_SECOND), (long long) ((now % NM_UTILS_NS_PER_SECOND) / 1000), + "TIMESTAMP_BOOTTIME=%lld.%06lld", (long long) (boottime / NM_UTILS_NS_PER_SECOND), (long long) ((boottime % NM_UTILS_NS_PER_SECOND) / 1000), + NULL); + } + break; +#endif + default: + syslog (syslog_priority, "%s", str_if_set (message, "")); + break; + } } void -nm_logging_syslog_openlog (gboolean debug) +nm_logging_syslog_openlog (const char *logging_backend) { - if (debug) - openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER); - else - openlog (G_LOG_DOMAIN, LOG_PID, LOG_DAEMON); + if (global.log_backend != LOG_BACKEND_GLIB) + g_return_if_reached (); - if (!syslog_opened) { - syslog_opened = TRUE; + if (!logging_backend) + logging_backend = ""NM_CONFIG_LOGGING_BACKEND_DEFAULT; - g_log_set_handler (G_LOG_DOMAIN, - G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, - nm_log_handler, - NULL); + if (strcmp (logging_backend, "debug") == 0) { + global.log_backend = LOG_BACKEND_SYSLOG; + openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER); +#if SYSTEMD_JOURNAL + } else if (strcmp (logging_backend, "syslog") != 0) { + if (strcmp (logging_backend, "journal-syslog-style") != 0) + global.log_backend = LOG_BACKEND_JOURNAL; + else + global.log_backend = LOG_BACKEND_JOURNAL_SYSLOG_STYLE; + + /* ensure we read a monotonic timestamp. Reading the timestamp the first + * time causes a logging message. We don't want to do that during _nm_log_impl. */ + nm_utils_get_monotonic_timestamp_ns (); +#endif + } else { + global.log_backend = LOG_BACKEND_SYSLOG; + openlog (G_LOG_DOMAIN, LOG_PID, LOG_DAEMON); } -} -void -nm_logging_syslog_closelog (void) -{ - if (syslog_opened) - closelog (); + g_log_set_handler (G_LOG_DOMAIN, + G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, + nm_log_handler, + NULL); } + diff --git a/src/nm-logging.h b/src/nm-logging.h index 077209f9..19b965f8 100644 --- a/src/nm-logging.h +++ b/src/nm-logging.h @@ -26,9 +26,9 @@ #error nm-test-utils.h must be included as last header #endif -#include -#include +#include "nm-logging.h" +#include "nm-default.h" #include "nm-macros-internal.h" /* Log domains */ @@ -57,18 +57,18 @@ typedef enum { /*< skip >*/ LOGD_CORE = (1LL << 20), /* Core daemon and policy stuff */ LOGD_DEVICE = (1LL << 21), /* Device state and activation */ LOGD_OLPC = (1LL << 22), - LOGD_WIMAX = (1LL << 23), - LOGD_INFINIBAND = (1LL << 24), - LOGD_FIREWALL = (1LL << 25), - LOGD_ADSL = (1LL << 26), - LOGD_BOND = (1LL << 27), - LOGD_VLAN = (1LL << 28), - LOGD_BRIDGE = (1LL << 29), - LOGD_DBUS_PROPS = (1LL << 30), - LOGD_TEAM = (1LL << 31), - LOGD_CONCHECK = (1LL << 32), - LOGD_DCB = (1LL << 33), /* Data Center Bridging */ - LOGD_DISPATCH = (1LL << 34), + LOGD_INFINIBAND = (1LL << 23), + LOGD_FIREWALL = (1LL << 24), + LOGD_ADSL = (1LL << 25), + LOGD_BOND = (1LL << 26), + LOGD_VLAN = (1LL << 27), + LOGD_BRIDGE = (1LL << 28), + LOGD_DBUS_PROPS = (1LL << 29), + LOGD_TEAM = (1LL << 30), + LOGD_CONCHECK = (1LL << 31), + LOGD_DCB = (1LL << 32), /* Data Center Bridging */ + LOGD_DISPATCH = (1LL << 33), + LOGD_AUDIT = (1LL << 34), __LOGD_MAX, LOGD_ALL = ((__LOGD_MAX - 1LL) << 1) - 1LL, @@ -91,7 +91,12 @@ typedef enum { /*< skip >*/ LOGL_WARN, LOGL_ERR, - LOGL_MAX + _LOGL_N_REAL, /* the number of actual logging levels */ + + _LOGL_OFF = _LOGL_N_REAL, /* special logging level that is always disabled. */ + _LOGL_KEEP, /* special logging level to indicate that the logging level should not be changed. */ + + _LOGL_N, /* the number of logging levels including "OFF" */ } NMLogLevel; #define nm_log_err(domain, ...) nm_log (LOGL_ERR, (domain), __VA_ARGS__) @@ -164,8 +169,7 @@ gboolean nm_logging_setup (const char *level, const char *domains, char **bad_domains, GError **error); -void nm_logging_syslog_openlog (gboolean debug); -void nm_logging_syslog_closelog (void); +void nm_logging_syslog_openlog (const char *logging_backend); /*****************************************************************************/ @@ -202,30 +206,30 @@ void nm_logging_syslog_closelog (void); * use. As with the _LOGD() macro familiy above, the exact implementation * depends on the file that uses them. * Still, it encourages a common pattern to have the common set of macros - * like _LOG2D(), _LOG2I(), etc. and have _LOG2t() which by default + * like _LOG2D(), _LOG2I(), etc. and have _LOG2T() which by default * is disabled at compile time. */ #define _NMLOG2_ENABLED(level) ( nm_logging_enabled ((level), (_NMLOG2_DOMAIN)) ) -#define _LOG2T(...) _NMLOG2 (LOGL_TRACE, __VA_ARGS__) +#define _LOG2t(...) _NMLOG2 (LOGL_TRACE, __VA_ARGS__) #define _LOG2D(...) _NMLOG2 (LOGL_DEBUG, __VA_ARGS__) #define _LOG2I(...) _NMLOG2 (LOGL_INFO , __VA_ARGS__) #define _LOG2W(...) _NMLOG2 (LOGL_WARN , __VA_ARGS__) #define _LOG2E(...) _NMLOG2 (LOGL_ERR , __VA_ARGS__) -#define _LOG2T_ENABLED(...) _NMLOG2_ENABLED (LOGL_TRACE, ##__VA_ARGS__) +#define _LOG2t_ENABLED(...) _NMLOG2_ENABLED (LOGL_TRACE, ##__VA_ARGS__) #define _LOG2D_ENABLED(...) _NMLOG2_ENABLED (LOGL_DEBUG, ##__VA_ARGS__) #define _LOG2I_ENABLED(...) _NMLOG2_ENABLED (LOGL_INFO , ##__VA_ARGS__) #define _LOG2W_ENABLED(...) _NMLOG2_ENABLED (LOGL_WARN , ##__VA_ARGS__) #define _LOG2E_ENABLED(...) _NMLOG2_ENABLED (LOGL_ERR , ##__VA_ARGS__) #ifdef NM_MORE_LOGGING -#define _LOG2t_ENABLED(...) _NMLOG2_ENABLED (LOGL_TRACE, ##__VA_ARGS__) -#define _LOG2t(...) _NMLOG2 (LOGL_TRACE, __VA_ARGS__) +#define _LOG2T_ENABLED(...) _NMLOG2_ENABLED (LOGL_TRACE, ##__VA_ARGS__) +#define _LOG2T(...) _NMLOG2 (LOGL_TRACE, __VA_ARGS__) #else /* still call the logging macros to get compile time checks, but they will be optimized out. */ -#define _LOG2t_ENABLED(...) ( FALSE && (_NMLOG2_ENABLED (LOGL_TRACE, ##__VA_ARGS__)) ) -#define _LOG2t(...) G_STMT_START { if (FALSE) { _NMLOG2 (LOGL_TRACE, __VA_ARGS__); } } G_STMT_END +#define _LOG2T_ENABLED(...) ( FALSE && (_NMLOG2_ENABLED (LOGL_TRACE, ##__VA_ARGS__)) ) +#define _LOG2T(...) G_STMT_START { if (FALSE) { _NMLOG2 (LOGL_TRACE, __VA_ARGS__); } } G_STMT_END #endif /*****************************************************************************/ diff --git a/src/nm-manager-glue.h b/src/nm-manager-glue.h deleted file mode 100644 index 37a6cf1f..00000000 --- a/src/nm-manager-glue.h +++ /dev/null @@ -1,416 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_manager_MARSHAL_H__ -#define __dbus_glib_marshal_nm_manager_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -/* NONE:BOXED,POINTER */ -extern void dbus_glib_marshal_nm_manager_VOID__BOXED_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_manager_VOID__BOXED_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__BOXED_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer data2); - GMarshalFunc_VOID__BOXED_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_VOID__BOXED_POINTER) (marshal_data ? marshal_data : cc->callback); - - callback (data1, - g_marshal_value_peek_boxed (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - data2); -} -#define dbus_glib_marshal_nm_manager_NONE__BOXED_POINTER dbus_glib_marshal_nm_manager_VOID__BOXED_POINTER - -/* NONE:BOOLEAN,POINTER */ -extern void dbus_glib_marshal_nm_manager_VOID__BOOLEAN_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_manager_VOID__BOOLEAN_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__BOOLEAN_POINTER) (gpointer data1, - gboolean arg_1, - gpointer arg_2, - gpointer data2); - GMarshalFunc_VOID__BOOLEAN_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_VOID__BOOLEAN_POINTER) (marshal_data ? marshal_data : cc->callback); - - callback (data1, - g_marshal_value_peek_boolean (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - data2); -} -#define dbus_glib_marshal_nm_manager_NONE__BOOLEAN_POINTER dbus_glib_marshal_nm_manager_VOID__BOOLEAN_POINTER - -/* NONE:POINTER */ -#define dbus_glib_marshal_nm_manager_VOID__POINTER g_cclosure_marshal_VOID__POINTER -#define dbus_glib_marshal_nm_manager_NONE__POINTER dbus_glib_marshal_nm_manager_VOID__POINTER - -/* NONE:BOXED,BOXED,BOXED,POINTER */ -extern void dbus_glib_marshal_nm_manager_VOID__BOXED_BOXED_BOXED_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_manager_VOID__BOXED_BOXED_BOXED_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__BOXED_BOXED_BOXED_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer arg_3, - gpointer arg_4, - gpointer data2); - GMarshalFunc_VOID__BOXED_BOXED_BOXED_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - - g_return_if_fail (n_param_values == 5); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_VOID__BOXED_BOXED_BOXED_POINTER) (marshal_data ? marshal_data : cc->callback); - - callback (data1, - g_marshal_value_peek_boxed (param_values + 1), - g_marshal_value_peek_boxed (param_values + 2), - g_marshal_value_peek_boxed (param_values + 3), - g_marshal_value_peek_pointer (param_values + 4), - data2); -} -#define dbus_glib_marshal_nm_manager_NONE__BOXED_BOXED_BOXED_POINTER dbus_glib_marshal_nm_manager_VOID__BOXED_BOXED_BOXED_POINTER - -/* NONE:STRING,STRING,POINTER */ -extern void dbus_glib_marshal_nm_manager_VOID__STRING_STRING_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_manager_VOID__STRING_STRING_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__STRING_STRING_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer arg_3, - gpointer data2); - GMarshalFunc_VOID__STRING_STRING_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - - g_return_if_fail (n_param_values == 4); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_VOID__STRING_STRING_POINTER) (marshal_data ? marshal_data : cc->callback); - - callback (data1, - g_marshal_value_peek_string (param_values + 1), - g_marshal_value_peek_string (param_values + 2), - g_marshal_value_peek_pointer (param_values + 3), - data2); -} -#define dbus_glib_marshal_nm_manager_NONE__STRING_STRING_POINTER dbus_glib_marshal_nm_manager_VOID__STRING_STRING_POINTER - -/* BOOLEAN:STRING,POINTER,POINTER */ -extern void dbus_glib_marshal_nm_manager_BOOLEAN__STRING_POINTER_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_manager_BOOLEAN__STRING_POINTER_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer arg_3, - gpointer data2); - GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - gboolean v_return; - - g_return_if_fail (return_value != NULL); - g_return_if_fail (n_param_values == 4); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_BOOLEAN__STRING_POINTER_POINTER) (marshal_data ? marshal_data : cc->callback); - - v_return = callback (data1, - g_marshal_value_peek_string (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - g_marshal_value_peek_pointer (param_values + 3), - data2); - - g_value_set_boolean (return_value, v_return); -} - -/* BOOLEAN:POINTER,POINTER */ -extern void dbus_glib_marshal_nm_manager_BOOLEAN__POINTER_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_manager_BOOLEAN__POINTER_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer data2); - GMarshalFunc_BOOLEAN__POINTER_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - gboolean v_return; - - g_return_if_fail (return_value != NULL); - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_BOOLEAN__POINTER_POINTER) (marshal_data ? marshal_data : cc->callback); - - v_return = callback (data1, - g_marshal_value_peek_pointer (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - data2); - - g_value_set_boolean (return_value, v_return); -} - -/* BOOLEAN:POINTER,POINTER,POINTER */ -extern void dbus_glib_marshal_nm_manager_BOOLEAN__POINTER_POINTER_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_manager_BOOLEAN__POINTER_POINTER_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER_POINTER_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer arg_3, - gpointer data2); - GMarshalFunc_BOOLEAN__POINTER_POINTER_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - gboolean v_return; - - g_return_if_fail (return_value != NULL); - g_return_if_fail (n_param_values == 4); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_BOOLEAN__POINTER_POINTER_POINTER) (marshal_data ? marshal_data : cc->callback); - - v_return = callback (data1, - g_marshal_value_peek_pointer (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - g_marshal_value_peek_pointer (param_values + 3), - data2); - - g_value_set_boolean (return_value, v_return); -} - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_manager_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_manager_methods[] = { - { (GCallback) impl_manager_get_devices, dbus_glib_marshal_nm_manager_BOOLEAN__POINTER_POINTER, 0 }, - { (GCallback) impl_manager_get_device_by_ip_iface, dbus_glib_marshal_nm_manager_BOOLEAN__STRING_POINTER_POINTER, 62 }, - { (GCallback) impl_manager_activate_connection, dbus_glib_marshal_nm_manager_NONE__BOXED_BOXED_BOXED_POINTER, 140 }, - { (GCallback) impl_manager_add_and_activate_connection, dbus_glib_marshal_nm_manager_NONE__BOXED_BOXED_BOXED_POINTER, 265 }, - { (GCallback) impl_manager_deactivate_connection, dbus_glib_marshal_nm_manager_NONE__BOXED_POINTER, 417 }, - { (GCallback) impl_manager_sleep, dbus_glib_marshal_nm_manager_NONE__BOOLEAN_POINTER, 494 }, - { (GCallback) impl_manager_enable, dbus_glib_marshal_nm_manager_NONE__BOOLEAN_POINTER, 544 }, - { (GCallback) impl_manager_get_permissions, dbus_glib_marshal_nm_manager_NONE__POINTER, 596 }, - { (GCallback) impl_manager_set_logging, dbus_glib_marshal_nm_manager_NONE__STRING_STRING_POINTER, 669 }, - { (GCallback) impl_manager_get_logging, dbus_glib_marshal_nm_manager_BOOLEAN__POINTER_POINTER_POINTER, 736 }, - { (GCallback) impl_manager_check_connectivity, dbus_glib_marshal_nm_manager_NONE__POINTER, 811 }, - { (GCallback) impl_manager_get_state, dbus_glib_marshal_nm_manager_BOOLEAN__POINTER_POINTER, 884 }, -}; - -const DBusGObjectInfo dbus_glib_nm_manager_object_info = { 1, - dbus_glib_nm_manager_methods, - 12, -"org.freedesktop.NetworkManager\0GetDevices\0S\0devices\0O\0F\0N\0ao\0\0org.freedesktop.NetworkManager\0GetDeviceByIpIface\0S\0iface\0I\0s\0device\0O\0F\0N\0o\0\0org.freedesktop.NetworkManager\0ActivateConnection\0A\0connection\0I\0o\0device\0I\0o\0specific_object\0I\0o\0active_connection\0O\0F\0N\0o\0\0org.freedesktop.NetworkManager\0AddAndActivateConnection\0A\0connection\0I\0a{sa{sv}}\0device\0I\0o\0specific_object\0I\0o\0path\0O\0F\0N\0o\0active_connection\0O\0F\0N\0o\0\0org.freedesktop.NetworkManager\0DeactivateConnection\0A\0active_connection\0I\0o\0\0org.freedesktop.NetworkManager\0Sleep\0A\0sleep\0I\0b\0\0org.freedesktop.NetworkManager\0Enable\0A\0enable\0I\0b\0\0org.freedesktop.NetworkManager\0GetPermissions\0A\0permissions\0O\0F\0N\0a{ss}\0\0org.freedesktop.NetworkManager\0SetLogging\0A\0level\0I\0s\0domains\0I\0s\0\0org.freedesktop.NetworkManager\0GetLogging\0S\0level\0O\0F\0N\0s\0domains\0O\0F\0N\0s\0\0org.freedesktop.NetworkManager\0CheckConnectivity\0A\0connectivity\0O\0F\0N\0u\0\0org.freedesktop.NetworkManager\0state\0S\0state\0O\0F\0N\0u\0\0\0", -"org.freedesktop.NetworkManager\0CheckPermissions\0org.freedesktop.NetworkManager\0StateChanged\0org.freedesktop.NetworkManager\0PropertiesChanged\0org.freedesktop.NetworkManager\0DeviceAdded\0org.freedesktop.NetworkManager\0DeviceRemoved\0\0", -"org.freedesktop.NetworkManager\0Devices\0devices\0read\0org.freedesktop.NetworkManager\0NetworkingEnabled\0networking_enabled\0read\0org.freedesktop.NetworkManager\0WirelessEnabled\0wireless_enabled\0readwrite\0org.freedesktop.NetworkManager\0WirelessHardwareEnabled\0wireless_hardware_enabled\0read\0org.freedesktop.NetworkManager\0WwanEnabled\0wwan_enabled\0readwrite\0org.freedesktop.NetworkManager\0WwanHardwareEnabled\0wwan_hardware_enabled\0read\0org.freedesktop.NetworkManager\0WimaxEnabled\0wimax_enabled\0readwrite\0org.freedesktop.NetworkManager\0WimaxHardwareEnabled\0wimax_hardware_enabled\0read\0org.freedesktop.NetworkManager\0ActiveConnections\0active_connections\0read\0org.freedesktop.NetworkManager\0PrimaryConnection\0primary_connection\0read\0org.freedesktop.NetworkManager\0PrimaryConnectionType\0primary_connection_type\0read\0org.freedesktop.NetworkManager\0Metered\0metered\0read\0org.freedesktop.NetworkManager\0ActivatingConnection\0activating_connection\0read\0org.freedesktop.NetworkManager\0Startup\0startup\0read\0org.freedesktop.NetworkManager\0Version\0version\0read\0org.freedesktop.NetworkManager\0State\0state\0read\0org.freedesktop.NetworkManager\0Connectivity\0connectivity\0read\0\0" -}; - diff --git a/src/nm-manager.c b/src/nm-manager.c index a1e4fb4f..ffc89ec0 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -26,20 +26,13 @@ #include #include #include -#include -#include -#include -#include -#include "gsystem-local-alloc.h" -#include "nm-glib-compat.h" +#include "nm-default.h" #include "nm-manager.h" -#include "nm-logging.h" -#include "nm-dbus-manager.h" +#include "nm-bus-manager.h" #include "nm-vpn-manager.h" #include "nm-device.h" #include "nm-device-generic.h" -#include "nm-dbus-glib-types.h" #include "nm-platform.h" #include "nm-rfkill-manager.h" #include "nm-dhcp-manager.h" @@ -58,65 +51,14 @@ #include "nm-activation-request.h" #include "nm-core-internal.h" #include "nm-config.h" +#include "nm-audit-manager.h" +#include "nm-dbus-compat.h" +#include "NetworkManagerUtils.h" -#define NM_AUTOIP_DBUS_SERVICE "org.freedesktop.nm_avahi_autoipd" -#define NM_AUTOIP_DBUS_IFACE "org.freedesktop.nm_avahi_autoipd" - -static gboolean impl_manager_get_devices (NMManager *manager, - GPtrArray **devices, - GError **err); - -static gboolean impl_manager_get_device_by_ip_iface (NMManager *self, - const char *iface, - char **out_object_path, - GError **error); - -static void impl_manager_activate_connection (NMManager *manager, - const char *connection_path, - const char *device_path, - const char *specific_object_path, - DBusGMethodInvocation *context); - -static void impl_manager_add_and_activate_connection (NMManager *manager, - GHashTable *settings, - const char *device_path, - const char *specific_object_path, - DBusGMethodInvocation *context); - -static void impl_manager_deactivate_connection (NMManager *manager, - const char *connection_path, - DBusGMethodInvocation *context); - -static void impl_manager_sleep (NMManager *manager, - gboolean do_sleep, - DBusGMethodInvocation *context); - -static void impl_manager_enable (NMManager *manager, - gboolean enable, - DBusGMethodInvocation *context); - -static void impl_manager_get_permissions (NMManager *manager, - DBusGMethodInvocation *context); - -static gboolean impl_manager_get_state (NMManager *manager, - guint32 *state, - GError **error); - -static void impl_manager_set_logging (NMManager *manager, - const char *level, - const char *domains, - DBusGMethodInvocation *context); - -static void impl_manager_get_logging (NMManager *manager, - char **level, - char **domains); - -static void impl_manager_check_connectivity (NMManager *manager, - DBusGMethodInvocation *context); - -#include "nm-manager-glue.h" +#include "nmdbus-manager.h" +#include "nmdbus-device.h" -static void add_device (NMManager *self, NMDevice *device, gboolean try_assume); +static gboolean add_device (NMManager *self, NMDevice *device, GError **error); static NMActiveConnection *_new_active_connection (NMManager *self, NMConnection *connection, @@ -132,15 +74,17 @@ static void rfkill_change (const char *desc, RfKillType rtype, gboolean enabled) static gboolean find_master (NMManager *self, NMConnection *connection, NMDevice *device, - NMConnection **out_master_connection, + NMSettingsConnection **out_master_connection, NMDevice **out_master_device, NMActiveConnection **out_master_ac, GError **error); static void nm_manager_update_state (NMManager *manager); -#define SSD_POKE_INTERVAL 120 -#define ORIGDEV_TAG "originating-device" +static void connection_changed (NMSettings *settings, NMConnection *connection, + NMManager *manager); + +#define TAG_ACTIVE_CONNETION_ADD_AND_ACTIVATE "act-con-add-and-activate" typedef struct { gboolean user_enabled; @@ -170,7 +114,11 @@ typedef struct { NMPolicy *policy; - NMDBusManager *dbus_mgr; + NMBusManager *dbus_mgr; + struct { + GDBusConnection *connection; + guint id; + } prop_filter; NMRfkillManager *rfkill_mgr; NMSettings *settings; @@ -182,7 +130,6 @@ typedef struct { NMVpnManager *vpn_manager; - DBusGProxy *aipd_proxy; NMSleepMonitor *sleep_monitor; GSList *auth_chains; @@ -199,11 +146,13 @@ typedef struct { #define NM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_MANAGER, NMManagerPrivate)) -G_DEFINE_TYPE (NMManager, nm_manager, G_TYPE_OBJECT) +G_DEFINE_TYPE (NMManager, nm_manager, NM_TYPE_EXPORTED_OBJECT) enum { DEVICE_ADDED, + INTERNAL_DEVICE_ADDED, DEVICE_REMOVED, + INTERNAL_DEVICE_REMOVED, STATE_CHANGED, CHECK_PERMISSIONS, USER_PERMISSIONS_CHANGED, @@ -220,6 +169,7 @@ enum { PROP_0, PROP_VERSION, PROP_STATE, + PROP_STATE_FILE, PROP_STARTUP, PROP_NETWORKING_ENABLED, PROP_WIRELESS_ENABLED, @@ -235,6 +185,8 @@ enum { PROP_ACTIVATING_CONNECTION, PROP_DEVICES, PROP_METERED, + PROP_GLOBAL_DNS_CONFIGURATION, + PROP_ALL_DEVICES, /* Not exported */ PROP_HOSTNAME, @@ -243,6 +195,25 @@ enum { LAST_PROP }; +NM_DEFINE_SINGLETON_INSTANCE (NMManager); + +/************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_CORE +#define _NMLOG_PREFIX_NAME "manager" +#define _NMLOG(level, ...) \ + G_STMT_START { \ + char __sbuf[32]; \ + const void *const __self = (self); \ + \ + nm_log ((level), _NMLOG_DOMAIN, \ + "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + (__self && __self != singleton_instance \ + ? (__self ? nm_sprintf_buf (__sbuf, "[%p]", __self) : "[]") \ + : "") \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } G_STMT_END /************************************************************************/ @@ -258,13 +229,13 @@ static gboolean active_connection_remove (NMManager *self, NMActiveConnection *active) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - gboolean notify = !!nm_active_connection_get_path (active); + gboolean notify = nm_exported_object_is_exported (NM_EXPORTED_OBJECT (active)); GSList *found; /* FIXME: switch to a GList for faster removal */ found = g_slist_find (priv->active_connections, active); if (found) { - NMConnection *connection; + NMSettingsConnection *connection; priv->active_connections = g_slist_remove (priv->active_connections, active); g_signal_emit (self, signals[ACTIVE_CONNECTION_REMOVED], 0, active); @@ -272,18 +243,18 @@ active_connection_remove (NMManager *self, NMActiveConnection *active) g_signal_handlers_disconnect_by_func (active, active_connection_default_changed, self); if ( nm_active_connection_get_assumed (active) - && (connection = nm_active_connection_get_connection (active)) - && nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) + && (connection = nm_active_connection_get_settings_connection (active)) + && nm_settings_connection_get_nm_generated_assumed (connection)) g_object_ref (connection); else connection = NULL; - g_object_unref (active); + nm_exported_object_clear_and_unexport (&active); if ( connection && nm_settings_has_connection (priv->settings, connection)) { nm_log_dbg (LOGD_DEVICE, "Assumed connection disconnected. Deleting generated connection '%s' (%s)", - nm_connection_get_id (connection), nm_connection_get_uuid (connection)); + nm_settings_connection_get_id (connection), nm_settings_connection_get_uuid (connection)); nm_settings_connection_delete (NM_SETTINGS_CONNECTION (connection), NULL, NULL); g_object_unref (connection); } @@ -380,7 +351,7 @@ active_connection_add (NMManager *self, NMActiveConnection *active) g_signal_emit (self, signals[ACTIVE_CONNECTION_ADDED], 0, active); /* Only notify D-Bus if the active connection is actually exported */ - if (nm_active_connection_get_path (active)) + if (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (active))) g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS); } @@ -395,19 +366,30 @@ find_ac_for_connection (NMManager *manager, NMConnection *connection) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); GSList *iter; - NMActiveConnection *ac; - NMConnection *ac_connection; - NMActiveConnectionState ac_state; - const char *uuid; + const char *uuid = NULL; + gboolean is_settings_connection; + + is_settings_connection = NM_IS_SETTINGS_CONNECTION (connection); + + if (!is_settings_connection) + uuid = nm_connection_get_uuid (connection); - uuid = nm_connection_get_uuid (connection); for (iter = priv->active_connections; iter; iter = iter->next) { - ac = iter->data; - ac_connection = nm_active_connection_get_connection (ac); - ac_state = nm_active_connection_get_state (ac); + NMActiveConnection *ac = iter->data; + NMSettingsConnection *con; - if ( !strcmp (nm_connection_get_uuid (ac_connection), uuid) - && (ac_state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)) + con = nm_active_connection_get_settings_connection (ac); + + /* depending on whether we have a NMSettingsConnection or a NMConnection, + * we lookup by UUID or by reference. */ + if (is_settings_connection) { + if (con != (NMSettingsConnection *) connection) + continue; + } else { + if (strcmp (uuid, nm_connection_get_uuid (NM_CONNECTION (con))) != 0) + continue; + } + if (nm_active_connection_get_state (ac) < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) return ac; } @@ -426,12 +408,12 @@ nm_manager_get_activatable_connections (NMManager *manager) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); GSList *all_connections = nm_settings_get_connections (priv->settings); GSList *connections = NULL, *iter; - NMConnection *connection; + NMSettingsConnection *connection; for (iter = all_connections; iter; iter = iter->next) { connection = iter->data; - if (!find_ac_for_connection (manager, connection)) + if (!find_ac_for_connection (manager, NM_CONNECTION (connection))) connections = g_slist_prepend (connections, connection); } @@ -451,7 +433,7 @@ active_connection_get_by_path (NMManager *manager, const char *path) for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) { NMActiveConnection *candidate = iter->data; - if (g_strcmp0 (path, nm_active_connection_get_path (candidate)) == 0) + if (g_strcmp0 (path, nm_exported_object_get_path (NM_EXPORTED_OBJECT (candidate))) == 0) return candidate; } return NULL; @@ -467,6 +449,9 @@ _config_changed_cb (NMConfig *config, NMConfigData *config_data, NMConfigChangeF NM_CONNECTIVITY_INTERVAL, nm_config_data_get_connectivity_interval (config_data), NM_CONNECTIVITY_RESPONSE, nm_config_data_get_connectivity_response (config_data), NULL); + + if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_GLOBAL_DNS_CONFIG)) + g_object_notify (G_OBJECT (self), NM_MANAGER_GLOBAL_DNS_CONFIGURATION); } /************************************************************************/ @@ -479,7 +464,7 @@ nm_manager_get_device_by_path (NMManager *manager, const char *path) g_return_val_if_fail (path != NULL, NULL); for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) { - if (!strcmp (nm_device_get_path (NM_DEVICE (iter->data)), path)) + if (!strcmp (nm_exported_object_get_path (NM_EXPORTED_OBJECT (iter->data)), path)) return NM_DEVICE (iter->data); } return NULL; @@ -526,22 +511,62 @@ find_device_by_ip_iface (NMManager *self, const gchar *iface) g_return_val_if_fail (iface != NULL, NULL); for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = g_slist_next (iter)) { - if (g_strcmp0 (nm_device_get_ip_iface (NM_DEVICE (iter->data)), iface) == 0) - return NM_DEVICE (iter->data); + NMDevice *candidate = iter->data; + + if ( nm_device_is_real (candidate) + && g_strcmp0 (nm_device_get_ip_iface (candidate), iface) == 0) + return candidate; } return NULL; } +/** + * find_device_by_iface: + * @self: the #NMManager + * @iface: the device interface to find + * @connection: a connection to ensure the returned device is compatible with + * @slave: a slave connection to ensure a master is compatible with + * + * Finds a device by interface name, preferring realized devices. If @slave + * is given, this function will only return master devices and will ensure + * @slave, when activated, can be a slave of the returned master device. If + * @connection is given, this function will only consider devices that are + * compatible with @connection. + * + * Returns: the matching #NMDevice + */ static NMDevice * -find_device_by_iface (NMManager *self, const gchar *iface) +find_device_by_iface (NMManager *self, + const char *iface, + NMConnection *connection, + NMConnection *slave) { + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + NMDevice *fallback = NULL; GSList *iter; - for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = g_slist_next (iter)) { - if (g_strcmp0 (nm_device_get_iface (NM_DEVICE (iter->data)), iface) == 0) - return NM_DEVICE (iter->data); + g_return_val_if_fail (iface != NULL, NULL); + + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *candidate = iter->data; + + if (strcmp (nm_device_get_iface (candidate), iface)) + continue; + if (connection && !nm_device_check_connection_compatible (candidate, connection)) + continue; + if (slave) { + if (!nm_device_is_master (candidate)) + continue; + if (!nm_device_check_slave_connection_compatible (candidate, slave)) + continue; + } + + if (nm_device_is_real (candidate)) + return candidate; + else if (!fallback) + fallback = candidate; } - return NULL; + return fallback; } static gboolean @@ -717,6 +742,7 @@ manager_device_state_changed (NMDevice *device, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); switch (new_state) { case NM_DEVICE_STATE_UNMANAGED: @@ -729,6 +755,10 @@ manager_device_state_changed (NMDevice *device, default: break; } + + if ( new_state == NM_DEVICE_STATE_UNAVAILABLE + || new_state == NM_DEVICE_STATE_DISCONNECTED) + nm_settings_device_added (priv->settings, device); } static void device_has_pending_action_changed (NMDevice *device, @@ -825,7 +855,7 @@ remove_device (NMManager *manager, if (quitting) nm_device_set_unmanaged_quitting (device); else - nm_device_set_unmanaged (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_REMOVED); + nm_device_set_unmanaged_flags (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_REMOVED); } else if (quitting && nm_config_get_configure_and_quit (nm_config_get ())) { nm_device_spawn_iface_helper (device); } @@ -836,12 +866,15 @@ remove_device (NMManager *manager, nm_settings_device_removed (priv->settings, device, quitting); priv->devices = g_slist_remove (priv->devices, device); - g_signal_emit (manager, signals[DEVICE_REMOVED], 0, device); - g_object_notify (G_OBJECT (manager), NM_MANAGER_DEVICES); - nm_device_removed (device); + if (nm_device_is_real (device)) { + g_signal_emit (manager, signals[DEVICE_REMOVED], 0, device); + g_object_notify (G_OBJECT (manager), NM_MANAGER_DEVICES); + nm_device_removed (device); + } + g_signal_emit (manager, signals[INTERNAL_DEVICE_REMOVED], 0, device); + g_object_notify (G_OBJECT (manager), NM_MANAGER_ALL_DEVICES); - nm_dbus_manager_unregister_object (priv->dbus_mgr, device); - g_object_unref (device); + nm_exported_object_clear_and_unexport (&device); check_if_startup_complete (manager); } @@ -852,53 +885,6 @@ device_removed_cb (NMDevice *device, gpointer user_data) remove_device (NM_MANAGER (user_data), device, FALSE, TRUE); } -static void -device_link_initialized_cb (NMDevice *device, gpointer user_data) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (user_data); - - nm_settings_device_added (priv->settings, device); -} - -static void -aipd_handle_event (DBusGProxy *proxy, - const char *event, - const char *iface, - const char *address, - gpointer user_data) -{ - NMManager *manager = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - GSList *iter; - gboolean handled = FALSE; - - if (!event || !iface) { - nm_log_warn (LOGD_AUTOIP4, "incomplete message received from avahi-autoipd"); - return; - } - - if ( (strcmp (event, "BIND") != 0) - && (strcmp (event, "CONFLICT") != 0) - && (strcmp (event, "UNBIND") != 0) - && (strcmp (event, "STOP") != 0)) { - nm_log_warn (LOGD_AUTOIP4, "unknown event '%s' received from avahi-autoipd", event); - return; - } - - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - NMDevice *candidate = NM_DEVICE (iter->data); - - if (!strcmp (nm_device_get_iface (candidate), iface)) { - nm_device_handle_autoip4_event (candidate, event, address); - handled = TRUE; - break; - } - } - - if (!handled) - nm_log_warn (LOGD_AUTOIP4, "(%s): unhandled avahi-autoipd event", iface); -} - NMState nm_manager_get_state (NMManager *manager) { @@ -915,10 +901,12 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMDeviceFactory *factory; const char *parent_name = NULL; - NMConnection *parent_connection; + NMSettingsConnection *parent_connection; NMDevice *parent, *first_compatible = NULL; GSList *iter; + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + factory = nm_device_factory_manager_find_factory_for_connection (connection); if (!factory) return NULL; @@ -927,8 +915,8 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection) if (!parent_name) return NULL; - /* Try as an interface name */ - parent = find_device_by_ip_iface (self, parent_name); + /* Try as an interface name of a parent device */ + parent = find_device_by_iface (self, parent_name, NULL, NULL); if (parent) return parent; @@ -938,7 +926,7 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection) return parent; /* Maybe a connection UUID */ - parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, parent_name); + parent_connection = nm_settings_get_connection_by_uuid (priv->settings, parent_name); if (!parent_connection) return NULL; @@ -948,11 +936,11 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection) for (iter = priv->devices; iter; iter = iter->next) { NMDevice *candidate = iter->data; - if (nm_device_get_connection (candidate) == parent_connection) + if (nm_device_get_settings_connection (candidate) == parent_connection) return candidate; if ( !first_compatible - && nm_device_check_connection_compatible (candidate, parent_connection)) + && nm_device_check_connection_compatible (candidate, NM_CONNECTION (parent_connection))) first_compatible = candidate; } @@ -997,9 +985,6 @@ get_virtual_iface_name (NMManager *self, factory = nm_device_factory_manager_find_factory_for_connection (connection); if (!factory) { - nm_log_warn (LOGD_DEVICE, "(%s) NetworkManager plugin for '%s' unavailable", - nm_connection_get_id (connection), - nm_connection_get_connection_type (connection)); g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, @@ -1013,8 +998,6 @@ get_virtual_iface_name (NMManager *self, connection, parent ? nm_device_get_ip_iface (parent) : NULL); if (!iface) { - nm_log_warn (LOGD_DEVICE, "(%s) failed to determine virtual interface name", - nm_connection_get_id (connection)); g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, @@ -1031,125 +1014,149 @@ get_virtual_iface_name (NMManager *self, * system_create_virtual_device: * @self: the #NMManager * @connection: the connection which might require a virtual device - * @error: the error set when return value is NULL * * If @connection requires a virtual device and one does not yet exist for it, * creates that device. * - * Returns: the #NMDevice if successfully created, %NULL if not + * Returns: A #NMDevice that was just realized; %NULL if none */ static NMDevice * -system_create_virtual_device (NMManager *self, NMConnection *connection, GError **error) +system_create_virtual_device (NMManager *self, NMConnection *connection) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMDeviceFactory *factory; - GSList *iter; - char *iface = NULL; + GSList *connections, *iter; + gs_free char *iface = NULL; NMDevice *device = NULL, *parent = NULL; - gboolean nm_owned = FALSE; + GError *error = NULL; g_return_val_if_fail (NM_IS_MANAGER (self), NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, NULL); - iface = get_virtual_iface_name (self, connection, &parent, error); - if (!iface) + iface = get_virtual_iface_name (self, connection, &parent, &error); + if (!iface) { + nm_log_warn (LOGD_DEVICE, "(%s) can't get a name of a virtual device: %s", + nm_connection_get_id (connection), error->message); + g_error_free (error); return NULL; + } - /* Make sure we didn't create a device for this connection already */ + /* See if there's a device that is already compatible with this connection */ for (iter = priv->devices; iter; iter = g_slist_next (iter)) { NMDevice *candidate = iter->data; if ( g_strcmp0 (nm_device_get_iface (candidate), iface) == 0 - || nm_device_check_connection_compatible (candidate, connection)) { - nm_log_dbg (LOGD_DEVICE, "(%s) already created virtual interface name %s", - nm_connection_get_id (connection), iface); - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "interface name '%s' already created", iface); - goto out; + && nm_device_check_connection_compatible (candidate, connection)) { + + if (nm_device_is_real (candidate)) { + nm_log_dbg (LOGD_DEVICE, "(%s) already created virtual interface name %s", + nm_connection_get_id (connection), iface); + return NULL; + } + + device = candidate; + break; } } - factory = nm_device_factory_manager_find_factory_for_connection (connection); - if (!factory) { - nm_log_err (LOGD_DEVICE, "(%s:%s) NetworkManager plugin for '%s' unavailable", - nm_connection_get_id (connection), iface, - nm_connection_get_connection_type (connection)); - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "NetworkManager plugin for '%s' unavailable", - nm_connection_get_connection_type (connection)); - goto out; - } + if (!device) { + /* No matching device found. Proceed creating a new one. */ - nm_owned = !nm_platform_link_get_by_ifname (NM_PLATFORM_GET, iface); + factory = nm_device_factory_manager_find_factory_for_connection (connection); + if (!factory) { + nm_log_err (LOGD_DEVICE, "(%s:%s) NetworkManager plugin for '%s' unavailable", + nm_connection_get_id (connection), iface, + nm_connection_get_connection_type (connection)); + return NULL; + } - device = nm_device_factory_create_virtual_device_for_connection (factory, - connection, - parent, - error); - if (device) { - if (nm_owned) - nm_device_set_nm_owned (device); + device = nm_device_factory_create_device (factory, iface, NULL, connection, NULL, &error); + if (!device) { + nm_log_warn (LOGD_DEVICE, "(%s) factory can't create the device: %s", + nm_connection_get_id (connection), error->message); + g_error_free (error); + return NULL; + } - /* If it was created by NM there's no connection to assume, but if it - * previously existed there might be one. - */ - add_device (self, device, !nm_owned); + if (!add_device (self, device, &error)) { + nm_log_warn (LOGD_DEVICE, "(%s) can't register the device with manager: %s", + nm_connection_get_id (connection), error->message); + g_error_free (error); + g_object_unref (device); + return NULL; + } + /* Add device takes a reference that NMManager still owns, so it's + * safe to unref here and still return @device. + */ g_object_unref (device); } -out: - g_free (iface); + /* Create backing resources if the device has any autoconnect connections */ + connections = nm_settings_get_connections (priv->settings); + for (iter = connections; iter; iter = g_slist_next (iter)) { + NMConnection *candidate = iter->data; + NMSettingConnection *s_con; + + if (!nm_device_check_connection_compatible (device, candidate)) + continue; + + s_con = nm_connection_get_setting_connection (candidate); + g_assert (s_con); + if (!nm_setting_connection_get_autoconnect (s_con)) + continue; + + /* Create any backing resources the device needs */ + if (!nm_device_create_and_realize (device, connection, parent, &error)) { + nm_log_warn (LOGD_DEVICE, "(%s) couldn't create the device: %s", + nm_connection_get_id (connection), error->message); + g_error_free (error); + remove_device (self, device, FALSE, TRUE); + return NULL; + } + break; + } + return device; } static void -system_create_virtual_devices (NMManager *self) +retry_connections_for_parent_device (NMManager *self, NMDevice *device) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *iter, *connections; + GSList *connections, *iter; - nm_log_dbg (LOGD_CORE, "creating virtual devices..."); + g_return_if_fail (device); connections = nm_settings_get_connections (priv->settings); for (iter = connections; iter; iter = g_slist_next (iter)) { - NMConnection *connection = iter->data; + NMConnection *candidate = iter->data; + NMDevice *parent; - /* We only create a virtual interface if the connection can autoconnect */ - if ( nm_connection_is_virtual (connection) - && nm_settings_connection_can_autoconnect (NM_SETTINGS_CONNECTION (connection))) - system_create_virtual_device (self, connection, NULL); + parent = find_parent_device_for_connection (self, candidate); + if (parent == device) + connection_changed (priv->settings, candidate, self); } - g_slist_free (connections); } static void -connection_added (NMSettings *settings, - NMSettingsConnection *settings_connection, - NMManager *manager) +connection_changed (NMSettings *settings, + NMConnection *connection, + NMManager *manager) { - NMConnection *connection = NM_CONNECTION (settings_connection); + NMDevice *device; - if (nm_connection_is_virtual (connection)) { - NMSettingConnection *s_con = nm_connection_get_setting_connection (connection); + if (!nm_connection_is_virtual (connection)) + return; - g_assert (s_con); - if (nm_setting_connection_get_autoconnect (s_con)) - system_create_virtual_device (manager, connection, NULL); - } -} + device = system_create_virtual_device (manager, connection); + if (!device) + return; -static void -connection_changed (NMSettings *settings, - NMSettingsConnection *connection, - NMManager *manager) -{ - /* FIXME: Some virtual devices may need to be updated in the future. */ + /* Maybe the device that was created was needed by some other + * connection's device (parent of a VLAN). Let the connections + * can use the newly created device as a parent know. */ + retry_connections_for_parent_device (manager, device); } static void @@ -1173,17 +1180,8 @@ system_unmanaged_devices_changed_cb (NMSettings *settings, const GSList *unmanaged_specs, *iter; unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings); - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - NMDevice *device = NM_DEVICE (iter->data); - gboolean unmanaged; - - unmanaged = nm_device_spec_match_list (device, unmanaged_specs); - nm_device_set_unmanaged (device, - NM_UNMANAGED_USER, - unmanaged, - unmanaged ? NM_DEVICE_STATE_REASON_NOW_UNMANAGED : - NM_DEVICE_STATE_REASON_NOW_MANAGED); - } + for (iter = priv->devices; iter; iter = g_slist_next (iter)) + nm_device_set_unmanaged_flags_by_device_spec (NM_DEVICE (iter->data), unmanaged_specs); } static void @@ -1405,7 +1403,7 @@ nm_manager_rfkill_update (NMManager *self, RfKillType rtype) static void device_auth_done_cb (NMAuthChain *chain, GError *auth_error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); @@ -1415,6 +1413,7 @@ device_auth_done_cb (NMAuthChain *chain, NMDevice *device; const char *permission; NMDeviceAuthRequestFunc callback; + NMAuthSubject *subject; g_assert (context); @@ -1428,6 +1427,7 @@ device_auth_done_cb (NMAuthChain *chain, g_assert (device); result = nm_auth_chain_get_result (chain, permission); + subject = nm_auth_chain_get_subject (chain); if (auth_error) { /* translate the auth error into a manager permission denied error */ @@ -1448,6 +1448,7 @@ device_auth_done_cb (NMAuthChain *chain, callback (device, context, + subject, error, nm_auth_chain_get_data (chain, "user-data")); @@ -1457,7 +1458,7 @@ device_auth_done_cb (NMAuthChain *chain, static void device_auth_request_cb (NMDevice *device, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, NMConnection *connection, const char *permission, gboolean allow_interaction, @@ -1482,7 +1483,6 @@ device_auth_request_cb (NMDevice *device, /* Ensure the subject has permissions for this connection */ if (connection && !nm_auth_is_subject_in_acl (connection, - nm_session_monitor_get (), subject, &error_desc)) { error = g_error_new_literal (NM_MANAGER_ERROR, @@ -1509,9 +1509,10 @@ device_auth_request_cb (NMDevice *device, nm_auth_chain_add_call (chain, permission, allow_interaction); done: - g_clear_object (&subject); if (error) - callback (device, context, error, user_data); + callback (device, context, subject, error, user_data); + + g_clear_object (&subject); g_clear_error (&error); } @@ -1533,12 +1534,13 @@ match_connection_filter (NMConnection *connection, gpointer user_data) * Returns: a #NMSettingsConnection to be assumed by the device, or %NULL if * the device does not support assuming existing connections. */ -static NMConnection * +static NMSettingsConnection * get_existing_connection (NMManager *manager, NMDevice *device, gboolean *out_generated) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); gs_free_slist GSList *connections = nm_manager_get_activatable_connections (manager); - NMConnection *connection = NULL, *matched; + NMConnection *connection = NULL; + NMSettingsConnection *matched; NMSettingsConnection *added = NULL; GError *error = NULL; NMDevice *master = NULL; @@ -1587,15 +1589,15 @@ get_existing_connection (NMManager *manager, NMDevice *device, gboolean *out_gen * the generated connection instead. */ connections = g_slist_reverse (g_slist_sort (connections, nm_settings_sort_connections)); - matched = nm_utils_match_connection (connections, - connection, - nm_device_has_carrier (device), - match_connection_filter, - device); + matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection (connections, + connection, + nm_device_has_carrier (device), + match_connection_filter, + device)); if (matched) { nm_log_info (LOGD_DEVICE, "(%s): found matching connection '%s'", nm_device_get_iface (device), - nm_connection_get_id (matched)); + nm_settings_connection_get_id (matched)); g_object_unref (connection); return matched; } @@ -1621,11 +1623,11 @@ get_existing_connection (NMManager *manager, NMDevice *device, gboolean *out_gen } g_object_unref (connection); - return added ? NM_CONNECTION (added) : NULL; + return added ? added : NULL; } static gboolean -assume_connection (NMManager *self, NMDevice *device, NMConnection *connection) +assume_connection (NMManager *self, NMDevice *device, NMSettingsConnection *connection) { NMActiveConnection *active, *master_ac; NMAuthSubject *subject; @@ -1643,12 +1645,12 @@ assume_connection (NMManager *self, NMDevice *device, NMConnection *connection) g_return_val_if_fail (nm_device_get_state (device) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); subject = nm_auth_subject_new_internal (); - active = _new_active_connection (self, connection, NULL, device, subject, &error); + active = _new_active_connection (self, NM_CONNECTION (connection), NULL, device, subject, &error); g_object_unref (subject); if (!active) { nm_log_warn (LOGD_DEVICE, "assumed connection %s failed to activate: (%d) %s", - nm_connection_get_path (connection), + nm_connection_get_path (NM_CONNECTION (connection)), error ? error->code : -1, error && error->message ? error->message : "(unknown)"); g_error_free (error); @@ -1657,11 +1659,11 @@ assume_connection (NMManager *self, NMDevice *device, NMConnection *connection) /* If the device is a slave or VLAN, find the master ActiveConnection */ master_ac = NULL; - if (find_master (self, connection, device, NULL, NULL, &master_ac, NULL) && master_ac) + if (find_master (self, NM_CONNECTION (connection), device, NULL, NULL, &master_ac, NULL) && master_ac) nm_active_connection_set_master (active, master_ac); nm_active_connection_set_assumed (active, TRUE); - nm_active_connection_export (active); + nm_exported_object_export (NM_EXPORTED_OBJECT (active)); active_connection_add (self, active); nm_device_queue_activation (device, NM_ACT_REQUEST (active)); g_object_unref (active); @@ -1670,16 +1672,27 @@ assume_connection (NMManager *self, NMDevice *device, NMConnection *connection) } static gboolean -recheck_assume_connection (NMDevice *device, gpointer user_data) +can_start_device (NMManager *self, NMDevice *device) { - NMManager *self = NM_MANAGER (user_data); - NMConnection *connection; - gboolean was_unmanaged = FALSE, success, generated; + return nm_device_is_real (device) + && !manager_sleeping (self) + && !nm_device_get_unmanaged_flags (device, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT); +} + +static gboolean +recheck_assume_connection (NMManager *self, NMDevice *device) +{ + NMSettingsConnection *connection; + gboolean was_unmanaged = FALSE, success, generated = FALSE; NMDeviceState state; - if (manager_sleeping (self)) + g_return_val_if_fail (NM_IS_MANAGER (self), FALSE); + g_return_val_if_fail (NM_IS_DEVICE (device), FALSE); + + if (nm_device_get_is_nm_owned (device)) return FALSE; - if (nm_device_get_unmanaged_flag (device, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT)) + + if (!can_start_device (self, device)) return FALSE; state = nm_device_get_state (device); @@ -1708,7 +1721,7 @@ recheck_assume_connection (NMDevice *device, gpointer user_data) NM_DEVICE_STATE_REASON_CONFIG_FAILED); /* Return default-unmanaged devices to their original state */ - if (nm_device_get_unmanaged_flag (device, NM_UNMANAGED_DEFAULT)) { + if (nm_device_get_unmanaged_flags (device, NM_UNMANAGED_DEFAULT)) { nm_device_state_changed (device, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_CONFIG_FAILED); @@ -1719,13 +1732,19 @@ recheck_assume_connection (NMDevice *device, gpointer user_data) nm_log_dbg (LOGD_DEVICE, "(%s): connection assumption failed. Deleting generated connection", nm_device_get_iface (device)); - nm_settings_connection_delete (NM_SETTINGS_CONNECTION (connection), NULL, NULL); + nm_settings_connection_delete (connection, NULL, NULL); } } return success; } +static void +recheck_assume_connection_cb (NMDevice *device, gpointer user_data) +{ + recheck_assume_connection (user_data, device); +} + static void device_ip_iface_changed (NMDevice *device, GParamSpec *pspec, @@ -1743,53 +1762,80 @@ device_ip_iface_changed (NMDevice *device, NMDevice *candidate = NM_DEVICE (iter->data); if ( candidate != device - && g_strcmp0 (nm_device_get_iface (candidate), ip_iface) == 0) { + && g_strcmp0 (nm_device_get_iface (candidate), ip_iface) == 0 + && nm_device_is_real (candidate)) { remove_device (self, candidate, FALSE, FALSE); break; } } } -static gboolean -notify_component_added (NMManager *self, GObject *component) +static void +device_iface_changed (NMDevice *device, + GParamSpec *pspec, + NMManager *self) { - GSList *iter; + /* Virtual connections may refer to the new device name as + * parent device, retry to activate them. + */ + retry_connections_for_parent_device (self, device); +} - for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) { - if (nm_device_notify_component_added (NM_DEVICE (iter->data), component)) - return TRUE; + +static void +device_realized (NMDevice *device, + GParamSpec *pspec, + NMManager *self) +{ + int ifindex; + + /* Emit D-Bus signals */ + g_signal_emit (self, signals[DEVICE_ADDED], 0, device); + g_object_notify (G_OBJECT (self), NM_MANAGER_DEVICES); + + /* Loopback device never gets managed */ + ifindex = nm_device_get_ifindex (device); + if (ifindex > 0 && nm_platform_link_get_type (NM_PLATFORM_GET, ifindex) == NM_LINK_TYPE_LOOPBACK) + return; + + if (!can_start_device (self, device)) + return; + + if ( !recheck_assume_connection (self, device) + && nm_device_get_managed (device)) { + nm_device_state_changed (device, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_REASON_NOW_MANAGED); } - return FALSE; } /** * add_device: * @self: the #NMManager * @device: the #NMDevice to add - * @try_assume: %TRUE if existing connection (if any) should be assumed + * @error: (out): the #GError * * If successful, this function will increase the references count of @device. * Callers should decrease the reference count. */ -static void -add_device (NMManager *self, NMDevice *device, gboolean try_assume) +static gboolean +add_device (NMManager *self, NMDevice *device, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - const char *iface, *driver, *type_desc; + const char *iface, *type_desc; const GSList *unmanaged_specs; - gboolean user_unmanaged, sleeping; - gboolean enabled = FALSE; RfKillType rtype; GSList *iter, *remove = NULL; - gboolean connection_assumed = FALSE; int ifindex; + const char *dbus_path; /* No duplicates */ ifindex = nm_device_get_ifindex (device); - if (ifindex > 0 && nm_manager_get_device_by_ifindex (self, ifindex)) - return; - if (find_device_by_iface (self, nm_device_get_iface (device))) - return; + if (ifindex > 0 && nm_manager_get_device_by_ifindex (self, ifindex)) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, + "A device with ifindex %d already exits", ifindex); + return FALSE; + } /* Remove existing devices owned by the new device; eg remove ethernet * ports that are owned by a WWAN modem, since udev may announce them @@ -1799,9 +1845,11 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume) * the child NMDevice entirely */ for (iter = priv->devices; iter; iter = iter->next) { - iface = nm_device_get_ip_iface (iter->data); - if (nm_device_owns_iface (device, iface)) - remove = g_slist_prepend (remove, iter->data); + NMDevice *candidate = iter->data; + + iface = nm_device_get_ip_iface (candidate); + if (nm_device_is_real (candidate) && nm_device_owns_iface (device, iface)) + remove = g_slist_prepend (remove, candidate); } for (iter = remove; iter; iter = iter->next) remove_device (self, NM_DEVICE (iter->data), FALSE, FALSE); @@ -1809,7 +1857,7 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume) priv->devices = g_slist_append (priv->devices, g_object_ref (device)); - g_signal_connect (device, "state-changed", + g_signal_connect (device, NM_DEVICE_STATE_CHANGED, G_CALLBACK (manager_device_state_changed), self); @@ -1821,14 +1869,22 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume) G_CALLBACK (device_removed_cb), self); - g_signal_connect (device, NM_DEVICE_LINK_INITIALIZED, - G_CALLBACK (device_link_initialized_cb), + g_signal_connect (device, NM_DEVICE_RECHECK_ASSUME, + G_CALLBACK (recheck_assume_connection_cb), self); g_signal_connect (device, "notify::" NM_DEVICE_IP_IFACE, G_CALLBACK (device_ip_iface_changed), self); + g_signal_connect (device, "notify::" NM_DEVICE_IFACE, + G_CALLBACK (device_iface_changed), + self); + + g_signal_connect (device, "notify::" NM_DEVICE_REAL, + G_CALLBACK (device_realized), + self); + if (priv->startup) { g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION, G_CALLBACK (device_has_pending_action_changed), @@ -1842,60 +1898,44 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume) rtype = nm_device_get_rfkill_type (device); if (rtype != RFKILL_TYPE_UNKNOWN) { nm_manager_rfkill_update (self, rtype); - enabled = radio_enabled_for_type (self, rtype, TRUE); - nm_device_set_enabled (device, enabled); + nm_device_set_enabled (device, radio_enabled_for_type (self, rtype, TRUE)); } iface = nm_device_get_iface (device); g_assert (iface); - type_desc = nm_device_get_type_desc (device); g_assert (type_desc); - driver = nm_device_get_driver (device); - if (!driver) - driver = "unknown"; - nm_log_info (LOGD_HW, "(%s): new %s device (carrier: %s, driver: '%s', ifindex: %d)", - iface, type_desc, - nm_device_has_capability (device, NM_DEVICE_CAP_CARRIER_DETECT) - ? (nm_device_has_carrier (device) ? "ON" : "OFF") - : "UNKNOWN", - driver, nm_device_get_ifindex (device)); unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings); - user_unmanaged = nm_device_spec_match_list (device, unmanaged_specs); - nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_USER, user_unmanaged); + nm_device_set_unmanaged_flags_initial (device, + NM_UNMANAGED_USER, + nm_device_spec_match_list (device, unmanaged_specs)); + nm_device_set_unmanaged_flags_initial (device, + NM_UNMANAGED_INTERNAL, + manager_sleeping (self)); - sleeping = manager_sleeping (self); - nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_INTERNAL, sleeping); + dbus_path = nm_exported_object_export (NM_EXPORTED_OBJECT (device)); + nm_log_info (LOGD_DEVICE, "(%s): new %s device (%s)", iface, type_desc, dbus_path); - nm_device_dbus_export (device); nm_device_finish_init (device); - if (try_assume) { - connection_assumed = recheck_assume_connection (device, self); - g_signal_connect (device, NM_DEVICE_RECHECK_ASSUME, - G_CALLBACK (recheck_assume_connection), self); - } + nm_settings_device_added (priv->settings, device); + g_signal_emit (self, signals[INTERNAL_DEVICE_ADDED], 0, device); + g_object_notify (G_OBJECT (self), NM_MANAGER_ALL_DEVICES); - if (!connection_assumed && nm_device_get_managed (device)) { - nm_device_state_changed (device, - NM_DEVICE_STATE_UNAVAILABLE, - NM_DEVICE_STATE_REASON_NOW_MANAGED); + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *d = iter->data; + + if (d != device) + nm_device_notify_new_device_added (d, device); } - /* Try to generate a default connection. If this fails because the link is - * not initialized, we will retry again in device_link_initialized_cb(). + /* Virtual connections may refer to the new device as + * parent device, retry to activate them. */ - nm_settings_device_added (priv->settings, device); - g_signal_emit (self, signals[DEVICE_ADDED], 0, device); - g_object_notify (G_OBJECT (self), NM_MANAGER_DEVICES); + retry_connections_for_parent_device (self, device); - notify_component_added (self, G_OBJECT (device)); - - /* New devices might be master interfaces for virtual interfaces; so we may - * need to create new virtual interfaces now. - */ - system_create_virtual_devices (self); + return TRUE; } /*******************************************************************/ @@ -1905,7 +1945,16 @@ factory_device_added_cb (NMDeviceFactory *factory, NMDevice *device, gpointer user_data) { - add_device (NM_MANAGER (user_data), device, TRUE); + GError *error = NULL; + + if (nm_device_realize_start (device, NULL, NULL, &error)) { + add_device (NM_MANAGER (user_data), device, NULL); + nm_device_realize_finish (device, NULL); + } else { + nm_log_warn (LOGD_DEVICE, "(%s): failed to realize device: %s", + nm_device_get_iface (device), error->message); + g_error_free (error); + } } static gboolean @@ -1913,7 +1962,15 @@ factory_component_added_cb (NMDeviceFactory *factory, GObject *component, gpointer user_data) { - return notify_component_added (NM_MANAGER (user_data), component); + GSList *iter; + + g_return_val_if_fail (NM_IS_MANAGER (user_data), FALSE); + + for (iter = NM_MANAGER_GET_PRIVATE (user_data)->devices; iter; iter = iter->next) { + if (nm_device_notify_component_added ((NMDevice *) iter->data, component)) + return TRUE; + } + return FALSE; } static void @@ -1936,23 +1993,51 @@ _register_device_factory (NMDeviceFactory *factory, gpointer user_data) static void platform_link_added (NMManager *self, int ifindex, - NMPlatformLink *plink) + const NMPlatformLink *plink) { NMDeviceFactory *factory; NMDevice *device = NULL; GError *error = NULL; + gboolean nm_plugin_missing = FALSE; + GSList *iter; g_return_if_fail (ifindex > 0); if (nm_manager_get_device_by_ifindex (self, ifindex)) return; + /* Let unrealized devices try to realize themselves with the link */ + for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) { + NMDevice *candidate = iter->data; + gboolean compatible = TRUE; + + if (strcmp (nm_device_get_iface (candidate), plink->name)) + continue; + + if (nm_device_is_real (candidate)) { + /* Ignore the link added event since there's already a realized + * device with the link's name. + */ + return; + } else if (nm_device_realize_start (candidate, plink, &compatible, &error)) { + /* Success */ + nm_device_realize_finish (candidate, plink); + return; + } + + nm_log_dbg (LOGD_DEVICE, "(%s): failed to realize from plink: '%s'", + plink->name, error->message); + g_clear_error (&error); + + /* Try next unrealized device */ + } + /* Try registered device factories */ factory = nm_device_factory_manager_find_factory_for_link_type (plink->type); if (factory) { gboolean ignore = FALSE; - device = nm_device_factory_new_link (factory, plink, &ignore, &error); + device = nm_device_factory_create_device (factory, plink->name, plink, NULL, &ignore, &error); if (!device) { if (!ignore) { nm_log_warn (LOGD_HW, "%s: factory failed to create device: %s", @@ -1970,9 +2055,9 @@ platform_link_added (NMManager *self, case NM_LINK_TYPE_OLPC_MESH: case NM_LINK_TYPE_TEAM: case NM_LINK_TYPE_WIFI: - case NM_LINK_TYPE_WIMAX: nm_log_info (LOGD_HW, "(%s): '%s' plugin not available; creating generic device", plink->name, nm_link_type_to_string (plink->type)); + nm_plugin_missing = TRUE; /* fall through */ default: device = nm_device_generic_new (plink); @@ -1981,8 +2066,17 @@ platform_link_added (NMManager *self, } if (device) { - add_device (self, device, plink->type != NM_LINK_TYPE_LOOPBACK); - g_object_unref (device); + if (nm_plugin_missing) + nm_device_set_nm_plugin_missing (device, TRUE); + if (nm_device_realize_start (device, plink, NULL, &error)) { + add_device (self, device, NULL); + nm_device_realize_finish (device, plink); + } else { + nm_log_warn (LOGD_DEVICE, "%s: failed to realize device: %s", + plink->name, error->message); + g_clear_error (&error); + } + g_object_unref (device); } } @@ -1995,25 +2089,42 @@ static gboolean _platform_link_cb_idle (PlatformLinkCbData *data) { NMManager *self = data->self; + const NMPlatformLink *l; - if (self) { - const NMPlatformLink *l; + if (!self) + goto out; - l = nm_platform_link_get (NM_PLATFORM_GET, data->ifindex); - if (l) { - NMPlatformLink pllink; + g_object_remove_weak_pointer (G_OBJECT (self), (gpointer *) &data->self); - pllink = *l; /* make a copy of the link instance */ - platform_link_added (self, data->ifindex, &pllink); - } else { - NMDevice *device; + l = nm_platform_link_get (NM_PLATFORM_GET, data->ifindex); + if (l) { + NMPlatformLink pllink; - device = nm_manager_get_device_by_ifindex (self, data->ifindex); - if (device) + pllink = *l; /* make a copy of the link instance */ + platform_link_added (self, data->ifindex, &pllink); + } else { + NMDevice *device; + GError *error = NULL; + + device = nm_manager_get_device_by_ifindex (self, data->ifindex); + if (device) { + if (nm_device_is_software (device)) { + /* Our software devices stick around until their connection is removed */ + if (!nm_device_unrealize (device, FALSE, &error)) { + nm_log_warn (LOGD_DEVICE, "(%s): failed to unrealize: %s", + nm_device_get_iface (device), + error->message); + g_clear_error (&error); + remove_device (self, device, FALSE, TRUE); + } + } else { + /* Hardware and external devices always get removed when their kernel link is gone */ remove_device (self, device, FALSE, TRUE); + } } - g_object_remove_weak_pointer (G_OBJECT (self), (gpointer *) &data->self); } + +out: g_slice_free (PlatformLinkCbData, data); return G_SOURCE_REMOVE; } @@ -2024,7 +2135,6 @@ platform_link_cb (NMPlatform *platform, int ifindex, NMPlatformLink *plink, NMPlatformSignalChangeType change_type, - NMPlatformReason reason, gpointer user_data) { PlatformLinkCbData *data; @@ -2113,44 +2223,67 @@ nm_manager_get_best_device_for_connection (NMManager *self, return NULL; } -static gboolean -impl_manager_get_devices (NMManager *manager, GPtrArray **devices, GError **err) +static void +_get_devices (NMManager *self, + GDBusMethodInvocation *context, + gboolean all_devices) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + gs_free const char **paths = NULL; + guint i; GSList *iter; - *devices = g_ptr_array_sized_new (g_slist_length (priv->devices)); + paths = g_new (const char *, g_slist_length (priv->devices) + 1); - for (iter = priv->devices; iter; iter = iter->next) - g_ptr_array_add (*devices, g_strdup (nm_device_get_path (NM_DEVICE (iter->data)))); + for (i = 0, iter = priv->devices; iter; iter = iter->next) { + const char *path; - return TRUE; + path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (iter->data)); + if ( path + && (all_devices || nm_device_is_real (iter->data))) + paths[i++] = path; + } + paths[i++] = NULL; + + g_dbus_method_invocation_return_value (context, + g_variant_new ("(^ao)", (char **) paths)); } -static gboolean +static void +impl_manager_get_devices (NMManager *self, + GDBusMethodInvocation *context) +{ + _get_devices (self, context, FALSE); +} + +static void +impl_manager_get_all_devices (NMManager *self, + GDBusMethodInvocation *context) +{ + _get_devices (self, context, TRUE); +} + +static void impl_manager_get_device_by_ip_iface (NMManager *self, - const char *iface, - char **out_object_path, - GError **error) + GDBusMethodInvocation *context, + const char *iface) { NMDevice *device; const char *path = NULL; device = find_device_by_ip_iface (self, iface); - if (device) { - path = nm_device_get_path (device); - if (path) - *out_object_path = g_strdup (path); - } + if (device) + path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (device)); if (path == NULL) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "No device found for the requested iface."); + g_dbus_method_invocation_return_error (context, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "No device found for the requested iface."); + } else { + g_dbus_method_invocation_return_value (context, + g_variant_new ("(o)", path)); } - - return path ? TRUE : FALSE; } static gboolean @@ -2213,7 +2346,7 @@ static gboolean find_master (NMManager *self, NMConnection *connection, NMDevice *device, - NMConnection **out_master_connection, + NMSettingsConnection **out_master_connection, NMDevice **out_master_device, NMActiveConnection **out_master_ac, GError **error) @@ -2222,8 +2355,8 @@ find_master (NMManager *self, NMSettingConnection *s_con; const char *master; NMDevice *master_device = NULL; - NMConnection *master_connection = NULL; - GSList *iter, *connections = NULL; + NMSettingsConnection *master_connection = NULL; + GSList *iter; s_con = nm_connection_get_setting_connection (connection); g_assert (s_con); @@ -2233,7 +2366,7 @@ find_master (NMManager *self, return TRUE; /* success, but no master */ /* Try as an interface name first */ - master_device = find_device_by_ip_iface (self, master); + master_device = find_device_by_iface (self, master, NULL, connection); if (master_device) { if (master_device == device) { g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, @@ -2241,8 +2374,8 @@ find_master (NMManager *self, return FALSE; } - master_connection = nm_device_get_connection (master_device); - if (master_connection && !is_compatible_with_slave (master_connection, connection)) { + master_connection = nm_device_get_settings_connection (master_device); + if (master_connection && !is_compatible_with_slave (NM_CONNECTION (master_connection), connection)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, "The active connection on %s is not a valid master for '%s'", nm_device_get_iface (master_device), @@ -2251,7 +2384,7 @@ find_master (NMManager *self, } } else { /* Try master as a connection UUID */ - master_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, master); + master_connection = nm_settings_get_connection_by_uuid (priv->settings, master); if (master_connection) { /* Check if the master connection is activated on some device already */ for (iter = priv->devices; iter; iter = g_slist_next (iter)) { @@ -2260,28 +2393,11 @@ find_master (NMManager *self, if (candidate == device) continue; - if (nm_device_get_connection (candidate) == master_connection) { + if (nm_device_get_settings_connection (candidate) == master_connection) { master_device = candidate; break; } } - } else { - /* Might be a virtual interface that hasn't been created yet, so - * look through the interface names of connections that require - * virtual interfaces and see if one of their virtual interface - * names matches the master. - */ - connections = nm_manager_get_activatable_connections (self); - for (iter = connections; iter && !master_connection; iter = g_slist_next (iter)) { - NMConnection *candidate = iter->data; - char *vname; - - vname = get_virtual_iface_name (self, candidate, NULL, NULL); - if (g_strcmp0 (master, vname) == 0 && is_compatible_with_slave (candidate, connection)) - master_connection = candidate; - g_free (vname); - } - g_slist_free (connections); } } @@ -2290,7 +2406,7 @@ find_master (NMManager *self, if (out_master_device) *out_master_device = master_device; if (out_master_ac && master_connection) - *out_master_ac = find_ac_for_connection (self, master_connection); + *out_master_ac = find_ac_for_connection (self, NM_CONNECTION (master_connection)); if (master_device || master_connection) return TRUE; @@ -2334,7 +2450,7 @@ ensure_master_active_connection (NMManager *self, NMAuthSubject *subject, NMConnection *connection, NMDevice *device, - NMConnection *master_connection, + NMSettingsConnection *master_connection, NMDevice *master_device, GError **error) { @@ -2350,13 +2466,13 @@ ensure_master_active_connection (NMManager *self, * compatible connection. If it's already activating we can just proceed. */ if (master_device) { - NMConnection *device_connection = nm_device_get_connection (master_device); + NMSettingsConnection *device_connection = nm_device_get_settings_connection (master_device); /* If we're passed a connection and a device, we require that connection * be already activated on the device, eg returned from find_master(). */ g_assert (!master_connection || master_connection == device_connection); - if (device_connection && !is_compatible_with_slave (device_connection, connection)) { + if (device_connection && !is_compatible_with_slave (NM_CONNECTION (device_connection), connection)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, "The active connection on %s is not a valid master for '%s'", nm_device_get_iface (master_device), @@ -2375,7 +2491,7 @@ ensure_master_active_connection (NMManager *self, /* If the device is disconnected, find a compatible connection and * activate it on the device. */ - if (master_state == NM_DEVICE_STATE_DISCONNECTED) { + if (master_state == NM_DEVICE_STATE_DISCONNECTED || !nm_device_is_real (master_device)) { GSList *connections; g_assert (master_connection == NULL); @@ -2383,15 +2499,15 @@ ensure_master_active_connection (NMManager *self, /* Find a compatible connection and activate this device using it */ connections = nm_manager_get_activatable_connections (self); for (iter = connections; iter; iter = g_slist_next (iter)) { - NMConnection *candidate = NM_CONNECTION (iter->data); + NMSettingsConnection *candidate = NM_SETTINGS_CONNECTION (iter->data); /* Ensure eg bond/team slave and the candidate master is a * bond/team master */ - if (!is_compatible_with_slave (candidate, connection)) + if (!is_compatible_with_slave (NM_CONNECTION (candidate), connection)) continue; - if (nm_device_check_connection_available (master_device, candidate, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) { + if (nm_device_check_connection_available (master_device, NM_CONNECTION (candidate), NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) { master_ac = nm_manager_activate_connection (self, candidate, NULL, @@ -2432,13 +2548,15 @@ ensure_master_active_connection (NMManager *self, continue; } - if (!nm_device_check_connection_available (candidate, master_connection, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) + if (!nm_device_check_connection_available (candidate, NM_CONNECTION (master_connection), NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) continue; found_device = TRUE; - master_state = nm_device_get_state (candidate); - if (master_state != NM_DEVICE_STATE_DISCONNECTED) - continue; + if (!nm_device_is_software (candidate)) { + master_state = nm_device_get_state (candidate); + if (nm_device_is_real (candidate) && master_state != NM_DEVICE_STATE_DISCONNECTED) + continue; + } master_ac = nm_manager_activate_connection (self, master_connection, @@ -2454,7 +2572,7 @@ ensure_master_active_connection (NMManager *self, /* Device described by master_connection may be a virtual one that's * not created yet. */ - if (!found_device && nm_connection_is_virtual (master_connection)) { + if (!found_device && nm_connection_is_virtual (NM_CONNECTION (master_connection))) { master_ac = nm_manager_activate_connection (self, master_connection, NULL, @@ -2470,7 +2588,7 @@ ensure_master_active_connection (NMManager *self, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, "No compatible disconnected device found for master connection %s.", - nm_connection_get_uuid (master_connection)); + nm_settings_connection_get_uuid (master_connection)); } else g_assert_not_reached (); @@ -2480,17 +2598,17 @@ ensure_master_active_connection (NMManager *self, /** * find_slaves: * @manager: #NMManager object - * @connection: the master #NMConnection to find slave connections for + * @connection: the master #NMSettingsConnection to find slave connections for * @device: the master #NMDevice for the @connection * - * Given an #NMConnection, attempts to find its slaves. If @connection is not + * Given an #NMSettingsConnection, attempts to find its slaves. If @connection is not * master, or has not any slaves, this will return %NULL. * * Returns: list of slave connections for given master @connection, or %NULL **/ static GSList * find_slaves (NMManager *manager, - NMConnection *connection, + NMSettingsConnection *connection, NMDevice *device) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); @@ -2499,7 +2617,7 @@ find_slaves (NMManager *manager, NMSettingConnection *s_con; const char *master; - s_con = nm_connection_get_setting_connection (connection); + s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); g_assert (s_con); master = nm_setting_connection_get_master (s_con); @@ -2512,7 +2630,7 @@ find_slaves (NMManager *manager, */ all_connections = nm_settings_get_connections (priv->settings); for (iter = all_connections; iter; iter = iter->next) { - NMConnection *master_connection = NULL; + NMSettingsConnection *master_connection = NULL; NMDevice *master_device = NULL; NMConnection *candidate = iter->data; @@ -2558,34 +2676,34 @@ out: static gboolean autoconnect_slaves (NMManager *manager, - NMConnection *master_connection, + NMSettingsConnection *master_connection, NMDevice *master_device, NMAuthSubject *subject) { GError *local_err = NULL; gboolean ret = FALSE; - if (should_connect_slaves (master_connection, master_device)) { + if (should_connect_slaves (NM_CONNECTION (master_connection), master_device)) { GSList *slaves, *iter; iter = slaves = find_slaves (manager, master_connection, master_device); ret = slaves != NULL; while (iter) { - NMConnection *slave_connection = iter->data; + NMSettingsConnection *slave_connection = iter->data; iter = iter->next; nm_log_dbg (LOGD_CORE, "will activate slave connection '%s' (%s) as a dependency for master '%s' (%s)", - nm_connection_get_id (slave_connection), - nm_connection_get_uuid (slave_connection), - nm_connection_get_id (master_connection), - nm_connection_get_uuid (master_connection)); + nm_settings_connection_get_id (slave_connection), + nm_settings_connection_get_uuid (slave_connection), + nm_settings_connection_get_id (master_connection), + nm_settings_connection_get_uuid (master_connection)); /* Schedule slave activation */ nm_manager_activate_connection (manager, slave_connection, NULL, - nm_manager_get_best_device_for_connection (manager, slave_connection, FALSE), + nm_manager_get_best_device_for_connection (manager, NM_CONNECTION (slave_connection), FALSE), subject, &local_err); if (local_err) { @@ -2605,13 +2723,14 @@ _internal_activate_vpn (NMManager *self, NMActiveConnection *active, GError **er g_assert (NM_IS_VPN_CONNECTION (active)); + nm_exported_object_export (NM_EXPORTED_OBJECT (active)); success = nm_vpn_manager_activate_connection (NM_MANAGER_GET_PRIVATE (self)->vpn_manager, NM_VPN_CONNECTION (active), error); - if (success) { - nm_active_connection_export (active); + if (success) g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS); - } + else + nm_exported_object_unexport (NM_EXPORTED_OBJECT (active)); return success; } @@ -2619,10 +2738,13 @@ static gboolean _internal_activate_device (NMManager *self, NMActiveConnection *active, GError **error) { NMDevice *device, *existing, *master_device = NULL; - NMConnection *connection; - NMConnection *master_connection = NULL; + NMConnection *applied; + NMSettingsConnection *connection; + NMSettingsConnection *master_connection = NULL; + NMConnection *existing_connection = NULL; NMActiveConnection *master_ac = NULL; - GError *local_err = NULL; + NMAuthSubject *subject; + char *error_desc = NULL; g_return_val_if_fail (NM_IS_MANAGER (self), FALSE); g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (active), FALSE); @@ -2630,100 +2752,55 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * g_assert (NM_IS_VPN_CONNECTION (active) == FALSE); - connection = nm_active_connection_get_connection (active); + connection = nm_active_connection_get_settings_connection (active); g_assert (connection); - device = nm_active_connection_get_device (active); - if (!device) { - if (!nm_connection_is_virtual (connection)) { - NMSettingConnection *s_con = nm_connection_get_setting_connection (connection); - - g_assert (s_con); - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Unsupported virtual interface type '%s'", - nm_setting_connection_get_connection_type (s_con)); - return FALSE; - } - - device = system_create_virtual_device (self, connection, &local_err); - if (!device) { - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Failed to create virtual interface: %s", - local_err ? local_err->message : "(unknown)"); - g_clear_error (&local_err); - return FALSE; - } + applied = nm_active_connection_get_applied_connection (active); - if (!nm_active_connection_set_device (active, device)) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "The device could not be activated with this connection"); - return FALSE; - } + device = nm_active_connection_get_device (active); + g_return_val_if_fail (device != NULL, FALSE); - /* A newly created device, if allowed to be managed by NM, will be - * in the UNAVAILABLE state here. To ensure it can be activated - * immediately, we transition it to DISCONNECTED. - */ - if ( nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE) - && (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE)) { - nm_device_state_changed (device, - NM_DEVICE_STATE_DISCONNECTED, - NM_DEVICE_STATE_REASON_NONE); - } - } else { - NMConnection *existing_connection = NULL; - NMAuthSubject *subject; - char *error_desc = NULL; - - /* If the device is active and its connection is not visible to the - * user that's requesting this new activation, fail, since other users - * should not be allowed to implicitly deactivate private connections - * by activating a connection of their own. - */ - existing_connection = nm_device_get_connection (device); - subject = nm_active_connection_get_subject (active); - if (existing_connection && - !nm_auth_is_subject_in_acl (existing_connection, - nm_session_monitor_get (), - subject, - &error_desc)) { - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - "Private connection already active on the device: %s", - error_desc); - g_free (error_desc); - return FALSE; - } + /* If the device is active and its connection is not visible to the + * user that's requesting this new activation, fail, since other users + * should not be allowed to implicitly deactivate private connections + * by activating a connection of their own. + */ + existing_connection = nm_device_get_applied_connection (device); + subject = nm_active_connection_get_subject (active); + if (existing_connection && + !nm_auth_is_subject_in_acl (existing_connection, + subject, + &error_desc)) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_PERMISSION_DENIED, + "Private connection already active on the device: %s", + error_desc); + g_free (error_desc); + return FALSE; } /* Final connection must be available on device */ - if (!nm_device_check_connection_available (device, connection, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) { + if (!nm_device_check_connection_available (device, applied, NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST, NULL)) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, "Connection '%s' is not available on the device %s at this time.", - nm_connection_get_id (connection), nm_device_get_iface (device)); + nm_settings_connection_get_id (connection), nm_device_get_iface (device)); return FALSE; } - /* If this is an autoconnect request, but the device isn't allowing autoconnect - * right now, we reject it. - */ - if (!nm_active_connection_get_user_requested (active) && - !nm_device_autoconnect_allowed (device)) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE, - "%s does not allow automatic connections at this time", - nm_device_get_iface (device)); - return FALSE; + /* Create any backing resources the device needs */ + if (!nm_device_is_real (device)) { + NMDevice *parent; + + parent = find_parent_device_for_connection (self, (NMConnection *) connection); + if (!nm_device_create_and_realize (device, (NMConnection *) connection, parent, error)) { + g_prefix_error (error, "%s failed to create resources: ", nm_device_get_iface (device)); + return FALSE; + } } /* Try to find the master connection/device if the connection has a dependency */ - if (!find_master (self, connection, device, + if (!find_master (self, applied, device, &master_connection, &master_device, &master_ac, error)) return FALSE; @@ -2734,17 +2811,17 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * if (master_connection || master_device) { if (master_connection) { nm_log_dbg (LOGD_CORE, "Activation of '%s' requires master connection '%s'", - nm_connection_get_id (connection), - nm_connection_get_id (master_connection)); + nm_settings_connection_get_id (connection), + nm_settings_connection_get_id (master_connection)); } if (master_device) { nm_log_dbg (LOGD_CORE, "Activation of '%s' requires master device '%s'", - nm_connection_get_id (connection), + nm_settings_connection_get_id (connection), nm_device_get_ip_iface (master_device)); } /* Ensure eg bond slave and the candidate master is a bond master */ - if (master_connection && !is_compatible_with_slave (master_connection, connection)) { + if (master_connection && !is_compatible_with_slave (NM_CONNECTION (master_connection), applied)) { g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED, "The master connection was not compatible"); return FALSE; @@ -2753,7 +2830,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * if (!master_ac) { master_ac = ensure_master_active_connection (self, nm_active_connection_get_subject (active), - connection, + applied, device, master_connection, master_device, @@ -2766,21 +2843,35 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError * } nm_active_connection_set_master (active, master_ac); - nm_log_dbg (LOGD_CORE, "Activation of '%s' depends on active connection %p", - nm_connection_get_id (connection), - master_ac); + nm_log_dbg (LOGD_CORE, "Activation of '%s' depends on active connection %p %s", + nm_settings_connection_get_id (connection), + master_ac, + str_if_set (nm_exported_object_get_path (NM_EXPORTED_OBJECT (master_ac)), "")); } /* Check slaves for master connection and possibly activate them */ autoconnect_slaves (self, connection, device, nm_active_connection_get_subject (active)); /* Disconnect the connection if connected or queued on another device */ - existing = nm_manager_get_connection_device (self, connection); + existing = nm_manager_get_connection_device (self, NM_CONNECTION (connection)); if (existing) nm_device_steal_connection (existing, connection); + if (nm_device_get_state (device) == NM_DEVICE_STATE_UNMANAGED) { + nm_device_state_changed (device, + NM_DEVICE_STATE_UNAVAILABLE, + NM_DEVICE_STATE_REASON_USER_REQUESTED); + } + + if ( nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_FOR_USER_REQUEST) + && (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE)) { + nm_device_state_changed (device, + NM_DEVICE_STATE_DISCONNECTED, + NM_DEVICE_STATE_REASON_USER_REQUESTED); + } + /* Export the new ActiveConnection to clients and start it on the device */ - nm_active_connection_export (active); + nm_exported_object_export (NM_EXPORTED_OBJECT (active)); g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS); nm_device_queue_activation (device, NM_ACT_REQUEST (active)); return TRUE; @@ -2824,8 +2915,8 @@ _internal_activate_generic (NMManager *self, NMActiveConnection *active, GError } static NMActiveConnection * -_new_vpn_active_connection (NMManager *self, - NMConnection *connection, +_new_vpn_active_connection (NMManager *self, + NMSettingsConnection *settings_connection, const char *specific_object, NMAuthSubject *subject, GError **error) @@ -2834,6 +2925,8 @@ _new_vpn_active_connection (NMManager *self, NMActiveConnection *parent = NULL; NMDevice *device = NULL; + g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); + if (specific_object) { /* Find the specific connection the client requested we use */ parent = active_connection_get_by_path (self, specific_object); @@ -2858,9 +2951,9 @@ _new_vpn_active_connection (NMManager *self, return NULL; } - return (NMActiveConnection *) nm_vpn_connection_new (connection, + return (NMActiveConnection *) nm_vpn_connection_new (settings_connection, device, - nm_active_connection_get_path (parent), + nm_exported_object_get_path (NM_EXPORTED_OBJECT (parent)), subject); } @@ -2872,7 +2965,9 @@ _new_active_connection (NMManager *self, NMAuthSubject *subject, GError **error) { + NMSettingsConnection *settings_connection = NULL; NMActiveConnection *existing_ac; + gboolean is_vpn; g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); @@ -2890,15 +2985,20 @@ _new_active_connection (NMManager *self, if (specific_object && g_strcmp0 (specific_object, "/") == 0) specific_object = NULL; - if (nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) { + is_vpn = nm_connection_is_type (NM_CONNECTION (connection), NM_SETTING_VPN_SETTING_NAME); + + if (NM_IS_SETTINGS_CONNECTION (connection)) + settings_connection = (NMSettingsConnection *) connection; + + if (is_vpn) { return _new_vpn_active_connection (self, - connection, + settings_connection, specific_object, subject, error); } - return (NMActiveConnection *) nm_act_request_new (connection, + return (NMActiveConnection *) nm_act_request_new (settings_connection, specific_object, subject, device); @@ -2910,7 +3010,7 @@ _internal_activation_failed (NMManager *self, const char *error_desc) { nm_log_dbg (LOGD_CORE, "Failed to activate '%s': %s", - nm_connection_get_id (nm_active_connection_get_connection (active)), + nm_active_connection_get_settings_connection_id (active), error_desc); if (nm_active_connection_get_state (active) <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { @@ -2948,7 +3048,7 @@ _internal_activation_auth_done (NMActiveConnection *active, /** * nm_manager_activate_connection(): * @self: the #NMManager - * @connection: the #NMConnection to activate on @device + * @connection: the #NMSettingsConnection to activate on @device * @specific_object: the specific object path, if any, for the activation * @device: the #NMDevice to activate @connection on * @subject: the subject which requested activation @@ -2965,7 +3065,7 @@ _internal_activation_auth_done (NMActiveConnection *active, */ NMActiveConnection * nm_manager_activate_connection (NMManager *self, - NMConnection *connection, + NMSettingsConnection *connection, const char *specific_object, NMDevice *device, NMAuthSubject *subject, @@ -2982,8 +3082,7 @@ nm_manager_activate_connection (NMManager *self, g_return_val_if_fail (*error == NULL, NULL); /* Ensure the subject has permissions for this connection */ - if (!nm_auth_is_subject_in_acl (connection, - nm_session_monitor_get (), + if (!nm_auth_is_subject_in_acl (NM_CONNECTION (connection), subject, &error_desc)) { g_set_error_literal (error, @@ -3002,7 +3101,7 @@ nm_manager_activate_connection (NMManager *self, for (iter = priv->authorizing_connections; iter; iter = g_slist_next (iter)) { active = iter->data; - if ( connection == nm_active_connection_get_connection (active) + if ( connection == nm_active_connection_get_settings_connection (active) && g_strcmp0 (nm_active_connection_get_specific_object (active), specific_object) == 0 && nm_active_connection_get_device (active) == device && nm_auth_subject_is_internal (nm_active_connection_get_subject (active)) @@ -3011,21 +3110,38 @@ nm_manager_activate_connection (NMManager *self, } active = _new_active_connection (self, - connection, + NM_CONNECTION (connection), specific_object, device, subject, error); if (active) { priv->authorizing_connections = g_slist_prepend (priv->authorizing_connections, active); - nm_active_connection_authorize (active, _internal_activation_auth_done, self, NULL); + nm_active_connection_authorize (active, NULL, _internal_activation_auth_done, self, NULL); } return active; } +/** + * validate_activation_request: + * @self: the #NMManager + * @context: the D-Bus context of the requestor + * @connection: the partial or complete #NMConnection to be activated + * @device_path: the object path of the device to be activated, or "/" + * @out_device: on successful reutrn, the #NMDevice to be activated with @connection + * @out_vpn: on successful return, %TRUE if @connection is a VPN connection + * @error: location to store an error on failure + * + * Performs basic validation on an activation request, including ensuring that + * the requestor is a valid Unix process, is not disallowed in @connection + * permissions, and that a device exists that can activate @connection. + * + * Returns: on success, the #NMAuthSubject representing the requestor, or + * %NULL on error + */ static NMAuthSubject * validate_activation_request (NMManager *self, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, NMConnection *connection, const char *device_path, NMDevice **out_device, @@ -3053,7 +3169,6 @@ validate_activation_request (NMManager *self, /* Ensure the subject has permissions for this connection */ if (!nm_auth_is_subject_in_acl (connection, - nm_session_monitor_get (), subject, &error_desc)) { g_set_error_literal (error, @@ -3098,11 +3213,11 @@ validate_activation_request (NMManager *self, } else device = nm_manager_get_best_device_for_connection (self, connection, TRUE); - if (!device) { + if (!device && !vpn) { gboolean is_software = nm_connection_is_virtual (connection); /* VPN and software-device connections don't need a device yet */ - if (!vpn && !is_software) { + if (!is_software) { g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, @@ -3118,11 +3233,19 @@ validate_activation_request (NMManager *self, if (!iface) goto error; - device = find_device_by_ip_iface (self, iface); + device = find_device_by_iface (self, iface, connection, NULL); g_free (iface); } } + if ((!vpn || device_path) && !device) { + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "Failed to find a compatible device for this connection"); + goto error; + } + *out_device = device; *out_vpn = vpn; return subject; @@ -3142,39 +3265,50 @@ _activation_auth_done (NMActiveConnection *active, gpointer user_data2) { NMManager *self = user_data1; - DBusGMethodInvocation *context = user_data2; + GDBusMethodInvocation *context = user_data2; GError *error = NULL; + NMAuthSubject *subject; + NMSettingsConnection *connection; + + subject = nm_active_connection_get_subject (active); + connection = nm_active_connection_get_settings_connection (active); if (success) { if (_internal_activate_generic (self, active, &error)) { - dbus_g_method_return (context, nm_active_connection_get_path (active)); + g_dbus_method_invocation_return_value (context, + g_variant_new ("(o)", + nm_exported_object_get_path (NM_EXPORTED_OBJECT (active)))); + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, TRUE, + subject, NULL); g_object_unref (active); return; } } else { error = g_error_new_literal (NM_MANAGER_ERROR, - NM_MANAGER_ERROR_PERMISSION_DENIED, - error_desc); + NM_MANAGER_ERROR_PERMISSION_DENIED, + error_desc); } g_assert (error); - dbus_g_method_return_error (context, error); + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, FALSE, + subject, error->message); _internal_activation_failed (self, active, error->message); + g_object_unref (active); - g_error_free (error); + g_dbus_method_invocation_take_error (context, error); } static void impl_manager_activate_connection (NMManager *self, + GDBusMethodInvocation *context, const char *connection_path, const char *device_path, - const char *specific_object_path, - DBusGMethodInvocation *context) + const char *specific_object_path) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMActiveConnection *active = NULL; NMAuthSubject *subject = NULL; - NMConnection *connection; + NMSettingsConnection *connection = NULL; NMDevice *device = NULL; gboolean is_vpn = FALSE; GError *error = NULL; @@ -3234,7 +3368,7 @@ impl_manager_activate_connection (NMManager *self, } g_assert (connection_path); - connection = (NMConnection *) nm_settings_get_connection_by_path (priv->settings, connection_path); + connection = nm_settings_get_connection_by_path (priv->settings, connection_path); if (!connection) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION, @@ -3244,7 +3378,7 @@ impl_manager_activate_connection (NMManager *self, subject = validate_activation_request (self, context, - connection, + NM_CONNECTION (connection), device_path, &device, &is_vpn, @@ -3253,7 +3387,7 @@ impl_manager_activate_connection (NMManager *self, goto error; active = _new_active_connection (self, - connection, + NM_CONNECTION (connection), specific_object_path, device, subject, @@ -3261,17 +3395,20 @@ impl_manager_activate_connection (NMManager *self, if (!active) goto error; - nm_active_connection_authorize (active, _activation_auth_done, self, context); + nm_active_connection_authorize (active, NULL, _activation_auth_done, self, context); g_clear_object (&subject); return; error: + if (connection) { + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ACTIVATE, connection, FALSE, + subject, error->message); + } g_clear_object (&active); g_clear_object (&subject); g_assert (error); - dbus_g_method_return_error (context, error); - g_error_free (error); + g_dbus_method_invocation_take_error (context, error); } /***********************************************************************/ @@ -3282,35 +3419,54 @@ typedef struct { } AddAndActivateInfo; static void -activation_add_done (NMSettings *self, +activation_add_done (NMSettings *settings, NMSettingsConnection *new_connection, GError *error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, + NMAuthSubject *subject, gpointer user_data) { AddAndActivateInfo *info = user_data; + NMManager *self; + gs_unref_object NMActiveConnection *active = NULL; GError *local = NULL; - if (!error) { - nm_active_connection_set_connection (info->active, NM_CONNECTION (new_connection)); + self = info->manager; + active = info->active; + g_slice_free (AddAndActivateInfo, info); - if (_internal_activate_generic (info->manager, info->active, &local)) { - dbus_g_method_return (context, - nm_connection_get_path (NM_CONNECTION (new_connection)), - nm_active_connection_get_path (info->active)); - goto done; + if (!error) { + nm_active_connection_set_settings_connection (active, new_connection); + + if (_internal_activate_generic (self, active, &local)) { + nm_settings_connection_commit_changes (new_connection, + NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION | NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED, + NULL, NULL); + g_dbus_method_invocation_return_value ( + context, + g_variant_new ("(oo)", + nm_connection_get_path (NM_CONNECTION (new_connection)), + nm_exported_object_get_path (NM_EXPORTED_OBJECT (active)))); + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD_ACTIVATE, + nm_active_connection_get_settings_connection (active), + TRUE, + nm_active_connection_get_subject (active), + NULL); + return; } error = local; } g_assert (error); - _internal_activation_failed (info->manager, info->active, error->message); - dbus_g_method_return_error (context, error); + _internal_activation_failed (self, active, error->message); + nm_settings_connection_delete (new_connection, NULL, NULL); + g_dbus_method_invocation_return_gerror (context, error); + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD_ACTIVATE, + NULL, + FALSE, + nm_active_connection_get_subject (active), + error->message); g_clear_error (&local); - -done: - g_object_unref (info->active); - g_free (info); } static void @@ -3322,29 +3478,39 @@ _add_and_activate_auth_done (NMActiveConnection *active, { NMManager *self = user_data1; NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - DBusGMethodInvocation *context = user_data2; + GDBusMethodInvocation *context = user_data2; AddAndActivateInfo *info; GError *error = NULL; if (success) { - info = g_malloc0 (sizeof (*info)); + NMConnection *connection; + + connection = g_object_steal_data (G_OBJECT (active), + TAG_ACTIVE_CONNETION_ADD_AND_ACTIVATE); + + info = g_slice_new (AddAndActivateInfo); info->manager = self; info->active = g_object_ref (active); /* Basic sender auth checks performed; try to add the connection */ nm_settings_add_connection_dbus (priv->settings, - nm_active_connection_get_connection (active), - TRUE, + connection, + FALSE, context, activation_add_done, info); + g_object_unref (connection); } else { g_assert (error_desc); error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, error_desc); - dbus_g_method_return_error (context, error); - g_error_free (error); + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD_ACTIVATE, + NULL, + FALSE, + nm_active_connection_get_subject (active), + error->message); + g_dbus_method_invocation_take_error (context, error); } g_object_unref (active); @@ -3352,10 +3518,10 @@ _add_and_activate_auth_done (NMActiveConnection *active, static void impl_manager_add_and_activate_connection (NMManager *self, - GHashTable *settings, + GDBusMethodInvocation *context, + GVariant *settings, const char *device_path, - const char *specific_object_path, - DBusGMethodInvocation *context) + const char *specific_object_path) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMConnection *connection = NULL; @@ -3380,12 +3546,8 @@ impl_manager_add_and_activate_connection (NMManager *self, * validate_activation_request()). */ connection = nm_simple_connection_new (); - if (settings && g_hash_table_size (settings)) { - GVariant *settings_dict = nm_utils_connection_hash_to_dict (settings); - - nm_connection_replace_settings (connection, settings_dict, NULL); - g_variant_unref (settings_dict); - } + if (settings && g_variant_n_children (settings)) + nm_connection_replace_settings (connection, settings, NULL); subject = validate_activation_request (self, context, @@ -3397,14 +3559,6 @@ impl_manager_add_and_activate_connection (NMManager *self, if (!subject) goto error; - /* AddAndActivate() requires a device to complete the connection with */ - if (!device) { - error = g_error_new_literal (NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "This connection requires an existing device."); - goto error; - } - all_connections = nm_settings_get_connections (priv->settings); if (vpn) { /* Try to fill the VPN's connection setting and name at least */ @@ -3444,20 +3598,24 @@ impl_manager_add_and_activate_connection (NMManager *self, if (!active) goto error; - nm_active_connection_authorize (active, _add_and_activate_auth_done, self, context); - g_object_unref (connection); + g_object_set_data_full (G_OBJECT (active), + TAG_ACTIVE_CONNETION_ADD_AND_ACTIVATE, + connection, + g_object_unref); + + nm_active_connection_authorize (active, connection, _add_and_activate_auth_done, self, context); g_object_unref (subject); return; error: + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD_ACTIVATE, NULL, FALSE, subject, error->message); g_clear_object (&connection); g_slist_free (all_connections); g_clear_object (&subject); g_clear_object (&active); g_assert (error); - dbus_g_method_return_error (context, error); - g_error_free (error); + g_dbus_method_invocation_take_error (context, error); } /***********************************************************************/ @@ -3468,7 +3626,6 @@ nm_manager_deactivate_connection (NMManager *manager, NMDeviceStateReason reason, GError **error) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); NMActiveConnection *active; gboolean success = FALSE; @@ -3484,7 +3641,7 @@ nm_manager_deactivate_connection (NMManager *manager, if (reason == NM_DEVICE_STATE_REASON_CONNECTION_REMOVED) vpn_reason = NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED; - if (nm_vpn_manager_deactivate_connection (priv->vpn_manager, NM_VPN_CONNECTION (active), vpn_reason)) + if (nm_vpn_connection_deactivate (NM_VPN_CONNECTION (active), vpn_reason, FALSE)) success = TRUE; else g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE, @@ -3506,19 +3663,23 @@ nm_manager_deactivate_connection (NMManager *manager, static void deactivate_net_auth_done_cb (NMAuthChain *chain, GError *auth_error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); GError *error = NULL; NMAuthCallResult result; + NMActiveConnection *active; + char *path; g_assert (context); priv->auth_chains = g_slist_remove (priv->auth_chains, chain); + path = nm_auth_chain_get_data (chain, "path"); result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL); + active = active_connection_get_by_path (self, path); if (auth_error) { nm_log_dbg (LOGD_CORE, "Disconnect request failed: %s", auth_error->message); @@ -3533,43 +3694,45 @@ deactivate_net_auth_done_cb (NMAuthChain *chain, } else { /* success; deactivation allowed */ if (!nm_manager_deactivate_connection (self, - nm_auth_chain_get_data (chain, "path"), + path, NM_DEVICE_STATE_REASON_USER_REQUESTED, &error)) g_assert (error); } + if (active) { + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DEACTIVATE, + nm_active_connection_get_settings_connection (active), + !error, + nm_auth_chain_get_subject (chain), + error ? error->message : NULL); + } + if (error) - dbus_g_method_return_error (context, error); + g_dbus_method_invocation_take_error (context, error); else - dbus_g_method_return (context); + g_dbus_method_invocation_return_value (context, NULL); - g_clear_error (&error); nm_auth_chain_unref (chain); } static void impl_manager_deactivate_connection (NMManager *self, - const char *active_path, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + const char *active_path) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMConnection *connection = NULL; + NMActiveConnection *ac; + NMSettingsConnection *connection = NULL; GError *error = NULL; NMAuthSubject *subject = NULL; - GSList *iter; NMAuthChain *chain; char *error_desc = NULL; /* Find the connection by its object path */ - for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) { - NMActiveConnection *ac = iter->data; - - if (g_strcmp0 (nm_active_connection_get_path (ac), active_path) == 0) { - connection = nm_active_connection_get_connection (ac); - break; - } - } + ac = active_connection_get_by_path (self, active_path); + if (ac) + connection = nm_active_connection_get_settings_connection (ac); if (!connection) { error = g_error_new_literal (NM_MANAGER_ERROR, @@ -3588,8 +3751,7 @@ impl_manager_deactivate_connection (NMManager *self, } /* Ensure the subject has permissions for this connection */ - if (!nm_auth_is_subject_in_acl (connection, - nm_session_monitor_get (), + if (!nm_auth_is_subject_in_acl (NM_CONNECTION (connection), subject, &error_desc)) { error = g_error_new_literal (NM_MANAGER_ERROR, @@ -3613,10 +3775,14 @@ impl_manager_deactivate_connection (NMManager *self, nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); done: + if (error) { + if (connection) { + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DEACTIVATE, connection, FALSE, + subject, error->message); + } + g_dbus_method_invocation_take_error (context, error); + } g_clear_object (&subject); - if (error) - dbus_g_method_return_error (context, error); - g_clear_error (&error); } static gboolean @@ -3651,7 +3817,7 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed) if (suspending && device_is_wake_on_lan (device)) continue; - nm_device_set_unmanaged (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_SLEEPING); + nm_device_set_unmanaged_flags (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_SLEEPING); } } else { nm_log_info (LOGD_SUSPEND, "%s...", waking_from_suspend ? "waking up" : "re-enabling"); @@ -3666,7 +3832,7 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed) if (nm_device_is_software (device)) continue; if (device_is_wake_on_lan (device)) - nm_device_set_unmanaged (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_SLEEPING); + nm_device_set_unmanaged_flags (device, NM_UNMANAGED_INTERNAL, TRUE, NM_DEVICE_STATE_REASON_SLEEPING); } } @@ -3700,9 +3866,9 @@ do_sleep_wake (NMManager *self, gboolean sleeping_changed) nm_device_set_enabled (device, enabled); } - g_object_set (G_OBJECT (device), NM_DEVICE_AUTOCONNECT, TRUE, NULL); + nm_device_set_autoconnect (device, TRUE); - nm_device_set_unmanaged (device, NM_UNMANAGED_INTERNAL, FALSE, NM_DEVICE_STATE_REASON_NOW_MANAGED); + nm_device_set_unmanaged_flags (device, NM_UNMANAGED_INTERNAL, FALSE, NM_DEVICE_STATE_REASON_NOW_MANAGED); } } @@ -3733,7 +3899,7 @@ _internal_sleep (NMManager *self, gboolean do_sleep) static void sleep_auth_done_cb (NMAuthChain *chain, GError *error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); @@ -3751,19 +3917,17 @@ sleep_auth_done_cb (NMAuthChain *chain, NM_MANAGER_ERROR_PERMISSION_DENIED, "Sleep/wake request failed: %s", error->message); - dbus_g_method_return_error (context, ret_error); - g_error_free (ret_error); + g_dbus_method_invocation_take_error (context, ret_error); } else if (result != NM_AUTH_CALL_RESULT_YES) { ret_error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, "Not authorized to sleep/wake"); - dbus_g_method_return_error (context, ret_error); - g_error_free (ret_error); + g_dbus_method_invocation_take_error (context, ret_error); } else { /* Auth success */ do_sleep = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "sleep")); _internal_sleep (self, do_sleep); - dbus_g_method_return (context); + g_dbus_method_invocation_return_value (context, NULL); } nm_auth_chain_unref (chain); @@ -3772,11 +3936,12 @@ sleep_auth_done_cb (NMAuthChain *chain, static void impl_manager_sleep (NMManager *self, - gboolean do_sleep, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + gboolean do_sleep) { NMManagerPrivate *priv; GError *error = NULL; + gs_unref_object NMAuthSubject *subject = NULL; #if 0 NMAuthChain *chain; const char *error_desc = NULL; @@ -3785,13 +3950,15 @@ impl_manager_sleep (NMManager *self, g_return_if_fail (NM_IS_MANAGER (self)); priv = NM_MANAGER_GET_PRIVATE (self); + subject = nm_auth_subject_new_unix_process_from_context (context); if (priv->sleeping == do_sleep) { error = g_error_new (NM_MANAGER_ERROR, NM_MANAGER_ERROR_ALREADY_ASLEEP_OR_AWAKE, "Already %s", do_sleep ? "asleep" : "awake"); - dbus_g_method_return_error (context, error); - g_error_free (error); + nm_audit_log_control_op (NM_AUDIT_OP_SLEEP_CONTROL, do_sleep ? "on" : "off", FALSE, subject, + error->message); + g_dbus_method_invocation_take_error (context, error); return; } @@ -3804,7 +3971,8 @@ impl_manager_sleep (NMManager *self, * D-Bus permissions to restrict the call to root. */ _internal_sleep (self, do_sleep); - dbus_g_method_return (context); + nm_audit_log_control_op (NM_AUDIT_OP_SLEEP_CONTROL, do_sleep ? "on" : "off", TRUE, subject, NULL); + g_dbus_method_invocation_return_value (context, NULL); return; #if 0 @@ -3817,21 +3985,20 @@ impl_manager_sleep (NMManager *self, error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, error_desc); - dbus_g_method_return_error (context, error); - g_error_free (error); + g_dbus_method_invocation_take_error (context, error); } #endif } static void -sleeping_cb (DBusGProxy *proxy, gpointer user_data) +sleeping_cb (NMSleepMonitor *monitor, gpointer user_data) { nm_log_dbg (LOGD_SUSPEND, "Received sleeping signal"); _internal_sleep (NM_MANAGER (user_data), TRUE); } static void -resuming_cb (DBusGProxy *proxy, gpointer user_data) +resuming_cb (NMSleepMonitor *monitor, gpointer user_data) { nm_log_dbg (LOGD_SUSPEND, "Received resuming signal"); _internal_sleep (NM_MANAGER (user_data), FALSE); @@ -3872,7 +4039,7 @@ _internal_enable (NMManager *self, gboolean enable) static void enable_net_done_cb (NMAuthChain *chain, GError *error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); @@ -3880,10 +4047,13 @@ enable_net_done_cb (NMAuthChain *chain, GError *ret_error = NULL; NMAuthCallResult result; gboolean enable; + NMAuthSubject *subject; g_assert (context); priv->auth_chains = g_slist_remove (priv->auth_chains, chain); + enable = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "enable")); + subject = nm_auth_chain_get_subject (chain); result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK); if (error) { @@ -3898,14 +4068,16 @@ enable_net_done_cb (NMAuthChain *chain, "Not authorized to enable/disable networking"); } else { /* Auth success */ - enable = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "enable")); _internal_enable (self, enable); - dbus_g_method_return (context); + g_dbus_method_invocation_return_value (context, NULL); + nm_audit_log_control_op (NM_AUDIT_OP_NET_CONTROL, enable ? "on" : "off", TRUE, + subject, NULL); } if (ret_error) { - dbus_g_method_return_error (context, ret_error); - g_error_free (ret_error); + nm_audit_log_control_op (NM_AUDIT_OP_NET_CONTROL, enable ? "on" : "off", FALSE, + subject, ret_error->message); + g_dbus_method_invocation_take_error (context, ret_error); } nm_auth_chain_unref (chain); @@ -3913,8 +4085,8 @@ enable_net_done_cb (NMAuthChain *chain, static void impl_manager_enable (NMManager *self, - gboolean enable, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + gboolean enable) { NMManagerPrivate *priv; NMAuthChain *chain; @@ -3945,24 +4117,23 @@ impl_manager_enable (NMManager *self, done: if (error) - dbus_g_method_return_error (context, error); - g_clear_error (&error); + g_dbus_method_invocation_take_error (context, error); } /* Permissions */ static void -get_perm_add_result (NMAuthChain *chain, GHashTable *results, const char *permission) +get_perm_add_result (NMAuthChain *chain, GVariantBuilder *results, const char *permission) { NMAuthCallResult result; result = nm_auth_chain_get_result (chain, permission); if (result == NM_AUTH_CALL_RESULT_YES) - g_hash_table_insert (results, (char *) permission, "yes"); + g_variant_builder_add (results, "{ss}", permission, "yes"); else if (result == NM_AUTH_CALL_RESULT_NO) - g_hash_table_insert (results, (char *) permission, "no"); + g_variant_builder_add (results, "{ss}", permission, "no"); else if (result == NM_AUTH_CALL_RESULT_AUTH) - g_hash_table_insert (results, (char *) permission, "auth"); + g_variant_builder_add (results, "{ss}", permission, "auth"); else { nm_log_dbg (LOGD_CORE, "unknown auth chain result %d", result); } @@ -3971,13 +4142,13 @@ get_perm_add_result (NMAuthChain *chain, GHashTable *results, const char *permis static void get_permissions_done_cb (NMAuthChain *chain, GError *error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); GError *ret_error; - GHashTable *results; + GVariantBuilder results; g_assert (context); @@ -3988,25 +4159,24 @@ get_permissions_done_cb (NMAuthChain *chain, NM_MANAGER_ERROR_PERMISSION_DENIED, "Permissions request failed: %s", error->message); - dbus_g_method_return_error (context, ret_error); - g_error_free (ret_error); + g_dbus_method_invocation_take_error (context, ret_error); } else { - results = g_hash_table_new (g_str_hash, g_str_equal); + g_variant_builder_init (&results, G_VARIANT_TYPE ("a{ss}")); - get_perm_add_result (chain, results, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK); - get_perm_add_result (chain, results, NM_AUTH_PERMISSION_SLEEP_WAKE); - get_perm_add_result (chain, results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI); - get_perm_add_result (chain, results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN); - get_perm_add_result (chain, results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX); - get_perm_add_result (chain, results, NM_AUTH_PERMISSION_NETWORK_CONTROL); - get_perm_add_result (chain, results, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED); - get_perm_add_result (chain, results, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN); - get_perm_add_result (chain, results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM); - get_perm_add_result (chain, results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN); - get_perm_add_result (chain, results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME); + get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK); + get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_SLEEP_WAKE); + get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI); + get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN); + get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX); + get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_NETWORK_CONTROL); + get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED); + get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN); + get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM); + get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN); + get_perm_add_result (chain, &results, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME); - dbus_g_method_return (context, results); - g_hash_table_destroy (results); + g_dbus_method_invocation_return_value (context, + g_variant_new ("(a{ss})", &results)); } nm_auth_chain_unref (chain); @@ -4014,7 +4184,7 @@ get_permissions_done_cb (NMAuthChain *chain, static void impl_manager_get_permissions (NMManager *self, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMAuthChain *chain; @@ -4025,8 +4195,7 @@ impl_manager_get_permissions (NMManager *self, error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, "Unable to authenticate request."); - dbus_g_method_return_error (context, error); - g_clear_error (&error); + g_dbus_method_invocation_take_error (context, error); return; } @@ -4044,25 +4213,26 @@ impl_manager_get_permissions (NMManager *self, nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, FALSE); } -static gboolean -impl_manager_get_state (NMManager *manager, guint32 *state, GError **error) +static void +impl_manager_get_state (NMManager *self, + GDBusMethodInvocation *context) { - nm_manager_update_state (manager); - *state = NM_MANAGER_GET_PRIVATE (manager)->state; - return TRUE; + nm_manager_update_state (self); + g_dbus_method_invocation_return_value (context, + g_variant_new ("(u)", NM_MANAGER_GET_PRIVATE (self)->state)); } static void -impl_manager_set_logging (NMManager *manager, +impl_manager_set_logging (NMManager *self, + GDBusMethodInvocation *context, const char *level, - const char *domains, - DBusGMethodInvocation *context) + const char *domains) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); GError *error = NULL; gulong caller_uid = G_MAXULONG; - if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &caller_uid, NULL)) { + if (!nm_bus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &caller_uid, NULL)) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, "Failed to get request UID."); @@ -4082,20 +4252,20 @@ impl_manager_set_logging (NMManager *manager, } done: - if (error) { - dbus_g_method_return_error (context, error); - g_error_free (error); - } else - dbus_g_method_return (context); + if (error) + g_dbus_method_invocation_take_error (context, error); + else + g_dbus_method_invocation_return_value (context, NULL); } static void impl_manager_get_logging (NMManager *manager, - char **level, - char **domains) + GDBusMethodInvocation *context) { - *level = g_strdup (nm_logging_level_to_string ()); - *domains = g_strdup (nm_logging_domains_to_string ()); + g_dbus_method_invocation_return_value (context, + g_variant_new ("(ss)", + nm_logging_level_to_string (), + nm_logging_domains_to_string ())); } static void @@ -4103,23 +4273,24 @@ connectivity_check_done (GObject *object, GAsyncResult *result, gpointer user_data) { - DBusGMethodInvocation *context = user_data; + GDBusMethodInvocation *context = user_data; NMConnectivityState state; GError *error = NULL; state = nm_connectivity_check_finish (NM_CONNECTIVITY (object), result, &error); - if (error) { - dbus_g_method_return_error (context, error); - g_error_free (error); - } else - dbus_g_method_return (context, state); + if (error) + g_dbus_method_invocation_take_error (context, error); + else { + g_dbus_method_invocation_return_value (context, + g_variant_new ("(u)", state)); + } } static void check_connectivity_auth_done_cb (NMAuthChain *chain, GError *auth_error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, gpointer user_data) { NMManager *self = NM_MANAGER (user_data); @@ -4148,29 +4319,26 @@ check_connectivity_auth_done_cb (NMAuthChain *chain, context); } - if (error) { - dbus_g_method_return_error (context, error); - g_error_free (error); - } + if (error) + g_dbus_method_invocation_take_error (context, error); nm_auth_chain_unref (chain); } static void -impl_manager_check_connectivity (NMManager *manager, - DBusGMethodInvocation *context) +impl_manager_check_connectivity (NMManager *self, + GDBusMethodInvocation *context) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMAuthChain *chain; GError *error = NULL; /* Validate the request */ - chain = nm_auth_chain_new_context (context, check_connectivity_auth_done_cb, manager); + chain = nm_auth_chain_new_context (context, check_connectivity_auth_done_cb, self); if (!chain) { error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED, "Unable to authenticate request."); - dbus_g_method_return_error (context, error); - g_clear_error (&error); + g_dbus_method_invocation_take_error (context, error); return; } @@ -4184,12 +4352,21 @@ start_factory (NMDeviceFactory *factory, gpointer user_data) nm_device_factory_start (factory); } -void -nm_manager_start (NMManager *self) +gboolean +nm_manager_start (NMManager *self, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + GSList *iter, *connections; guint i; + if (!nm_settings_start (priv->settings, error)) + return FALSE; + + g_signal_connect (NM_PLATFORM_GET, + NM_PLATFORM_SIGNAL_LINK_CHANGED, + G_CALLBACK (platform_link_cb), + self); + /* Set initial radio enabled/disabled state */ for (i = 0; i < RFKILL_TYPE_MAX; i++) { RadioState *rstate = &priv->radio_states[i]; @@ -4203,9 +4380,9 @@ nm_manager_start (NMManager *self) if (rstate->desc) { nm_log_info (LOGD_RFKILL, "%s %s by radio killswitch; %s by state file", - rstate->desc, - (rstate->hw_enabled && rstate->sw_enabled) ? "enabled" : "disabled", - rstate->user_enabled ? "enabled" : "disabled"); + rstate->desc, + (rstate->hw_enabled && rstate->sw_enabled) ? "enabled" : "disabled", + rstate->user_enabled ? "enabled" : "disabled"); } enabled = radio_enabled_for_rstate (rstate, TRUE); manager_update_radio_enabled (self, rstate, enabled); @@ -4219,19 +4396,28 @@ nm_manager_start (NMManager *self) system_hostname_changed_cb (priv->settings, NULL, self); /* Start device factories */ + nm_device_factory_manager_load_factories (_register_device_factory, self); nm_device_factory_manager_for_each_factory (start_factory, NULL); platform_query_devices (self); - /* - * Connections added before the manager is started do not emit + /* Load VPN plugins */ + priv->vpn_manager = g_object_ref (nm_vpn_manager_get ()); + + /* Connections added before the manager is started do not emit * connection-added signals thus devices have to be created manually. */ - system_create_virtual_devices (self); + nm_log_dbg (LOGD_CORE, "creating virtual devices..."); + connections = nm_settings_get_connections (priv->settings); + for (iter = connections; iter; iter = iter->next) + connection_changed (priv->settings, NM_CONNECTION (iter->data), self); + g_slist_free (connections); priv->devices_inited = TRUE; check_if_startup_complete (self); + + return TRUE; } void @@ -4360,7 +4546,7 @@ policy_default_device_changed (GObject *object, GParamSpec *pspec, gpointer user g_signal_connect (priv->primary_connection, NM_ACTIVE_CONNECTION_DEVICE_METERED_CHANGED, G_CALLBACK (connection_metered_changed), self); } - nm_log_dbg (LOGD_CORE, "PrimaryConnection now %s", ac ? nm_active_connection_get_id (ac) : "(none)"); + nm_log_dbg (LOGD_CORE, "PrimaryConnection now %s", ac ? nm_active_connection_get_settings_connection_id (ac) : "(none)"); g_object_notify (G_OBJECT (self), NM_MANAGER_PRIMARY_CONNECTION); g_object_notify (G_OBJECT (self), NM_MANAGER_PRIMARY_CONNECTION_TYPE); nm_manager_update_metered (self); @@ -4395,164 +4581,310 @@ policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer u if (ac != priv->activating_connection) { g_clear_object (&priv->activating_connection); priv->activating_connection = ac ? g_object_ref (ac) : NULL; - nm_log_dbg (LOGD_CORE, "ActivatingConnection now %s", ac ? nm_active_connection_get_id (ac) : "(none)"); + nm_log_dbg (LOGD_CORE, "ActivatingConnection now %s", ac ? nm_active_connection_get_settings_connection_id (ac) : "(none)"); g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVATING_CONNECTION); } } #define NM_PERM_DENIED_ERROR "org.freedesktop.NetworkManager.PermissionDenied" -#define DEV_PERM_DENIED_ERROR "org.freedesktop.NetworkManager.Device.PermissionDenied" + +typedef struct { + NMManager *self; + GDBusConnection *connection; + GDBusMessage *message; + NMAuthSubject *subject; + const char *permission; + const char *audit_op; + char *audit_prop_value; + GType interface_type; + const char *glib_propname; +} PropertyFilterData; + +static void +free_property_filter_data (PropertyFilterData *pfd) +{ + g_object_unref (pfd->self); + g_object_unref (pfd->connection); + g_object_unref (pfd->message); + g_clear_object (&pfd->subject); + g_free (pfd->audit_prop_value); + g_slice_free (PropertyFilterData, pfd); +} static void prop_set_auth_done_cb (NMAuthChain *chain, GError *error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, /* NULL */ gpointer user_data) { - NMManager *self = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - DBusConnection *connection; + PropertyFilterData *pfd = user_data; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (pfd->self); NMAuthCallResult result; - DBusMessage *reply = NULL, *message; - const char *permission, *prop; - GObject *obj; - gboolean set_enabled = TRUE; + GDBusMessage *reply = NULL; + const char *error_message; + gs_unref_object NMExportedObject *object = NULL; + const NMGlobalDnsConfig *global_dns; + gs_unref_variant GVariant *value = NULL; + GVariant *args; priv->auth_chains = g_slist_remove (priv->auth_chains, chain); + result = nm_auth_chain_get_result (chain, pfd->permission); + if (error || (result != NM_AUTH_CALL_RESULT_YES)) { + reply = g_dbus_message_new_method_error (pfd->message, + NM_PERM_DENIED_ERROR, + (error_message = "Not authorized to perform this operation")); + if (error) + error_message = error->message; + goto done; + } - message = nm_auth_chain_get_data (chain, "message"); - permission = nm_auth_chain_get_data (chain, "permission"); - prop = nm_auth_chain_get_data (chain, "prop"); - set_enabled = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "enabled")); - obj = nm_auth_chain_get_data (chain, "object"); + object = NM_EXPORTED_OBJECT (nm_bus_manager_get_registered_object (priv->dbus_mgr, + g_dbus_message_get_path (pfd->message))); + if (!object) { + reply = g_dbus_message_new_method_error (pfd->message, + "org.freedesktop.DBus.Error.UnknownObject", + (error_message = "Object doesn't exist.")); + goto done; + } - result = nm_auth_chain_get_result (chain, permission); - if (error || (result != NM_AUTH_CALL_RESULT_YES)) { - reply = dbus_message_new_error (message, - NM_IS_DEVICE (obj) ? DEV_PERM_DENIED_ERROR : NM_PERM_DENIED_ERROR, - "Not authorized to perform this operation"); + /* do some extra type checking... */ + if (!nm_exported_object_get_interface_by_type (object, pfd->interface_type)) { + reply = g_dbus_message_new_method_error (pfd->message, + "org.freedesktop.DBus.Error.InvalidArgs", + (error_message = "Object is of unexpected type.")); + goto done; + } + + args = g_dbus_message_get_body (pfd->message); + g_variant_get (args, "(&s&sv)", NULL, NULL, &value); + g_assert (pfd->glib_propname); + + if (!strcmp (pfd->glib_propname, NM_MANAGER_GLOBAL_DNS_CONFIGURATION)) { + g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE ("a{sv}"))); + global_dns = nm_config_data_get_global_dns_config (nm_config_get_data (priv->config)); + + if (global_dns && !nm_global_dns_config_is_internal (global_dns)) { + reply = g_dbus_message_new_method_error (pfd->message, + NM_PERM_DENIED_ERROR, + (error_message = "Global DNS configuration already set via configuration file")); + goto done; + } + /* ... but set the property on the @object itself. It would be correct to set the property + * on the skeleton interface, but as it is now, the result is the same. */ + g_object_set (object, pfd->glib_propname, value, NULL); } else { - g_object_set (obj, prop, set_enabled, NULL); - reply = dbus_message_new_method_return (message); + g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)); + /* the same here */ + g_object_set (object, pfd->glib_propname, g_variant_get_boolean (value), NULL); } - g_assert (reply); - connection = nm_auth_chain_get_data (chain, "connection"); - g_assert (connection); - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); + reply = g_dbus_message_new_method_reply (pfd->message); + g_dbus_message_set_body (reply, g_variant_new_tuple (NULL, 0)); + error_message = NULL; +done: + nm_audit_log_control_op (pfd->audit_op, pfd->audit_prop_value, !error_message, pfd->subject, error_message); + g_dbus_connection_send_message (pfd->connection, reply, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + NULL, NULL); + g_object_unref (reply); nm_auth_chain_unref (chain); + + free_property_filter_data (pfd); } -static DBusHandlerResult -prop_filter (DBusConnection *connection, - DBusMessage *message, - void *user_data) +static gboolean +do_set_property_check (gpointer user_data) { - NMManager *self = NM_MANAGER (user_data); - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - DBusMessageIter iter; - DBusMessageIter sub; - const char *propiface = NULL; - const char *propname = NULL; - const char *glib_propname = NULL, *permission = NULL; - DBusMessage *reply = NULL; - gboolean set_enabled = FALSE; - NMAuthSubject *subject = NULL; + PropertyFilterData *pfd = user_data; + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (pfd->self); + GDBusMessage *reply = NULL; NMAuthChain *chain; - GObject *obj; - - /* The sole purpose of this function is to validate property accesses - * on the NMManager object since dbus-glib doesn't yet give us this - * functionality. - */ - - if (!dbus_message_is_method_call (message, DBUS_INTERFACE_PROPERTIES, "Set")) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - dbus_message_iter_init (message, &iter); - - /* Get the D-Bus interface of the property to set */ - if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - dbus_message_iter_get_basic (&iter, &propiface); - if (!propiface || (strcmp (propiface, NM_DBUS_INTERFACE) && strcmp (propiface, NM_DBUS_INTERFACE_DEVICE))) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - dbus_message_iter_next (&iter); - - /* Get the property name that's going to be set */ - if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - dbus_message_iter_get_basic (&iter, &propname); - dbus_message_iter_next (&iter); - - if (!strcmp (propname, "WirelessEnabled")) { - glib_propname = NM_MANAGER_WIRELESS_ENABLED; - permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI; - } else if (!strcmp (propname, "WwanEnabled")) { - glib_propname = NM_MANAGER_WWAN_ENABLED; - permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN; - } else if (!strcmp (propname, "WimaxEnabled")) { - glib_propname = NM_MANAGER_WIMAX_ENABLED; - permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX; - } else if (!strcmp (propname, "Autoconnect")) { - glib_propname = NM_DEVICE_AUTOCONNECT; - permission = NM_AUTH_PERMISSION_NETWORK_CONTROL; - } else - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - /* Get the new value for the property */ - if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_VARIANT) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - dbus_message_iter_recurse (&iter, &sub); - if (dbus_message_iter_get_arg_type (&sub) != DBUS_TYPE_BOOLEAN) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - dbus_message_iter_get_basic (&sub, &set_enabled); - - /* Make sure the object exists */ - obj = dbus_g_connection_lookup_g_object (dbus_connection_get_g_connection (connection), - dbus_message_get_path (message)); - if (!obj) { - reply = dbus_message_new_error (message, NM_PERM_DENIED_ERROR, - "Object does not exist"); - goto out; - } + const char *error_message = NULL; - subject = nm_auth_subject_new_unix_process_from_message (connection, message); - if (!subject) { - reply = dbus_message_new_error (message, NM_PERM_DENIED_ERROR, - "Could not determine request UID."); + pfd->subject = nm_auth_subject_new_unix_process_from_message (pfd->connection, pfd->message); + if (!pfd->subject) { + reply = g_dbus_message_new_method_error (pfd->message, + NM_PERM_DENIED_ERROR, + (error_message = "Could not determine request UID.")); goto out; } /* Validate the user request */ - chain = nm_auth_chain_new_subject (subject, NULL, prop_set_auth_done_cb, self); + chain = nm_auth_chain_new_subject (pfd->subject, NULL, prop_set_auth_done_cb, pfd); if (!chain) { - reply = dbus_message_new_error (message, NM_PERM_DENIED_ERROR, - "Could not authenticate request."); + reply = g_dbus_message_new_method_error (pfd->message, + NM_PERM_DENIED_ERROR, + (error_message = "Could not authenticate request.")); goto out; } priv->auth_chains = g_slist_append (priv->auth_chains, chain); - nm_auth_chain_set_data (chain, "prop", g_strdup (glib_propname), g_free); - nm_auth_chain_set_data (chain, "permission", g_strdup (permission), g_free); - nm_auth_chain_set_data (chain, "enabled", GUINT_TO_POINTER (set_enabled), NULL); - nm_auth_chain_set_data (chain, "message", dbus_message_ref (message), (GDestroyNotify) dbus_message_unref); - nm_auth_chain_set_data (chain, "connection", dbus_connection_ref (connection), (GDestroyNotify) dbus_connection_unref); - nm_auth_chain_set_data (chain, "object", g_object_ref (obj), (GDestroyNotify) g_object_unref); - nm_auth_chain_add_call (chain, permission, TRUE); + nm_auth_chain_add_call (chain, pfd->permission, TRUE); out: if (reply) { - dbus_connection_send (connection, reply, NULL); - dbus_message_unref (reply); + nm_audit_log_control_op (pfd->audit_op, pfd->audit_prop_value, FALSE, pfd->subject, error_message); + g_dbus_connection_send_message (pfd->connection, reply, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + NULL, NULL); + g_object_unref (reply); + free_property_filter_data (pfd); } - g_clear_object (&subject); - return DBUS_HANDLER_RESULT_HANDLED; + return FALSE; +} + +static GDBusMessage * +prop_filter (GDBusConnection *connection, + GDBusMessage *message, + gboolean incoming, + gpointer user_data) +{ + gs_unref_object NMManager *self = NULL; + GVariant *args; + const char *propiface = NULL; + const char *propname = NULL; + const char *glib_propname = NULL, *permission = NULL; + const char *audit_op = NULL; + GType interface_type = G_TYPE_INVALID; + PropertyFilterData *pfd; + const GVariantType *expected_type = G_VARIANT_TYPE_BOOLEAN; + gs_unref_variant GVariant *value = NULL; + + self = g_weak_ref_get (user_data); + if (!self) + return message; + + /* The sole purpose of this function is to validate property accesses on the + * NMManager object since gdbus doesn't give us this functionality. + */ + + /* Only filter org.freedesktop.DBus.Properties.Set calls */ + if ( !incoming + || g_dbus_message_get_message_type (message) != G_DBUS_MESSAGE_TYPE_METHOD_CALL + || g_strcmp0 (g_dbus_message_get_interface (message), DBUS_INTERFACE_PROPERTIES) != 0 + || g_strcmp0 (g_dbus_message_get_member (message), "Set") != 0) + return message; + + args = g_dbus_message_get_body (message); + if (!g_variant_is_of_type (args, G_VARIANT_TYPE ("(ssv)"))) + return message; + g_variant_get (args, "(&s&sv)", &propiface, &propname, &value); + + /* Only filter calls to filtered properties, on existing objects */ + if (!strcmp (propiface, NM_DBUS_INTERFACE)) { + if (!strcmp (propname, "WirelessEnabled")) { + glib_propname = NM_MANAGER_WIRELESS_ENABLED; + permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI; + audit_op = NM_AUDIT_OP_RADIO_CONTROL; + } else if (!strcmp (propname, "WwanEnabled")) { + glib_propname = NM_MANAGER_WWAN_ENABLED; + permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN; + audit_op = NM_AUDIT_OP_RADIO_CONTROL; + } else if (!strcmp (propname, "WimaxEnabled")) { + glib_propname = NM_MANAGER_WIMAX_ENABLED; + permission = NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX; + audit_op = NM_AUDIT_OP_RADIO_CONTROL; + } else if (!strcmp (propname, "GlobalDnsConfiguration")) { + glib_propname = NM_MANAGER_GLOBAL_DNS_CONFIGURATION; + permission = NM_AUTH_PERMISSION_SETTINGS_MODIFY_GLOBAL_DNS; + audit_op = NM_AUDIT_OP_NET_CONTROL; + expected_type = G_VARIANT_TYPE ("a{sv}"); + } else + return message; + interface_type = NMDBUS_TYPE_MANAGER_SKELETON; + } else if (!strcmp (propiface, NM_DBUS_INTERFACE_DEVICE)) { + if (!strcmp (propname, "Autoconnect")) { + glib_propname = NM_DEVICE_AUTOCONNECT; + permission = NM_AUTH_PERMISSION_NETWORK_CONTROL; + audit_op = NM_AUDIT_OP_DEVICE_AUTOCONNECT; + } else if (!strcmp (propname, "Managed")) { + glib_propname = NM_DEVICE_MANAGED; + permission = NM_AUTH_PERMISSION_NETWORK_CONTROL; + audit_op = NM_AUDIT_OP_DEVICE_MANAGED; + } else + return message; + interface_type = NMDBUS_TYPE_DEVICE_SKELETON; + } else + return message; + + if (!g_variant_is_of_type (value, expected_type)) + return message; + + /* This filter function is called from a gdbus worker thread which we can't + * make other D-Bus calls from. In particular, we cannot call + * org.freedesktop.DBus.GetConnectionUnixUser to find the remote UID. + */ + pfd = g_slice_new0 (PropertyFilterData); + pfd->self = self; + self = NULL; + pfd->connection = g_object_ref (connection); + pfd->message = message; + pfd->permission = permission; + pfd->interface_type = interface_type; + pfd->glib_propname = glib_propname; + pfd->audit_op = audit_op; + if (g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN)) { + pfd->audit_prop_value = g_strdup_printf ("%s:%d", pfd->glib_propname, + g_variant_get_boolean (value)); + } else + pfd->audit_prop_value = g_strdup (pfd->glib_propname); + + g_idle_add (do_set_property_check, pfd); + + return NULL; +} + +/******************************************************************************/ + +static int +_set_prop_filter_free2 (gpointer user_data) +{ + g_slice_free (GWeakRef, user_data); + return G_SOURCE_REMOVE; +} + +static void +_set_prop_filter_free (gpointer user_data) +{ + g_weak_ref_clear (user_data); + + /* Delay the final deletion of the user_data. There is a race when + * calling g_dbus_connection_remove_filter() that the callback and user_data + * might have been copied and being executed after the destroy function + * runs (bgo #704568). + * This doesn't really fix the race, but it should work well enough. */ + g_timeout_add_seconds (2, _set_prop_filter_free2, user_data); +} + +static void +_set_prop_filter (NMManager *self, GDBusConnection *connection) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + + nm_assert ((!priv->prop_filter.connection) == (!priv->prop_filter.id)); + + if (priv->prop_filter.connection == connection) + return; + + if (priv->prop_filter.connection) { + g_dbus_connection_remove_filter (priv->prop_filter.connection, priv->prop_filter.id); + priv->prop_filter.id = 0; + g_clear_object (&priv->prop_filter.connection); + } + if (connection) { + GWeakRef *wptr; + + wptr = g_slice_new (GWeakRef); + g_weak_ref_init (wptr, self); + priv->prop_filter.id = g_dbus_connection_add_filter (connection, prop_filter, wptr, _set_prop_filter_free); + priv->prop_filter.connection = g_object_ref (connection); + } } +/******************************************************************************/ + static void authority_changed_cb (NMAuthManager *auth_manager, gpointer user_data) { @@ -4689,7 +5021,7 @@ periodic_update_active_connection_timestamps (gpointer user_data) NMSettingsConnection *connection; if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { - connection = NM_SETTINGS_CONNECTION (nm_active_connection_get_connection (ac)); + connection = nm_active_connection_get_settings_connection (ac); nm_settings_connection_update_timestamp (connection, (guint64) time (NULL), FALSE); } } @@ -4698,148 +5030,126 @@ periodic_update_active_connection_timestamps (gpointer user_data) } static void -dbus_connection_changed_cb (NMDBusManager *dbus_mgr, - DBusConnection *dbus_connection, +dbus_connection_changed_cb (NMBusManager *dbus_mgr, + GDBusConnection *connection, gpointer user_data) { - NMManager *self = NM_MANAGER (user_data); - gboolean success; - - if (dbus_connection) { - /* Only fails on ENOMEM */ - success = dbus_connection_add_filter (dbus_connection, prop_filter, self, NULL); - g_assert (success); - } + _set_prop_filter (NM_MANAGER (user_data), connection); } /**********************************************************************/ -static NMManager *singleton = NULL; +NM_DEFINE_SINGLETON_REGISTER (NMManager); NMManager * nm_manager_get (void) { - g_assert (singleton); - return singleton; + g_assert (singleton_instance); + return singleton_instance; } NMConnectionProvider * nm_connection_provider_get (void) { - g_assert (singleton); - g_assert (NM_MANAGER_GET_PRIVATE (singleton)->settings); - return NM_CONNECTION_PROVIDER (NM_MANAGER_GET_PRIVATE (singleton)->settings); + g_assert (singleton_instance); + g_assert (NM_MANAGER_GET_PRIVATE (singleton_instance)->settings); + return NM_CONNECTION_PROVIDER (NM_MANAGER_GET_PRIVATE (singleton_instance)->settings); } NMManager * -nm_manager_new (NMSettings *settings, - const char *state_file, - gboolean initial_net_enabled, - gboolean initial_wifi_enabled, - gboolean initial_wwan_enabled, - gboolean initial_wimax_enabled) +nm_manager_setup (const char *state_file, + gboolean initial_net_enabled, + gboolean initial_wifi_enabled, + gboolean initial_wwan_enabled) { - NMManagerPrivate *priv; - DBusConnection *dbus_connection; - NMConfigData *config_data; + NMManager *self; - g_assert (settings); + g_assert (singleton_instance == NULL); - /* Can only be called once */ - g_assert (singleton == NULL); - singleton = (NMManager *) g_object_new (NM_TYPE_MANAGER, NULL); - g_assert (singleton); + self = g_object_new (NM_TYPE_MANAGER, + NM_MANAGER_NETWORKING_ENABLED, initial_net_enabled, + NM_MANAGER_WIRELESS_ENABLED, initial_wifi_enabled, + NM_MANAGER_WWAN_ENABLED, initial_wwan_enabled, + NM_MANAGER_STATE_FILE, state_file, + NULL); + nm_assert (NM_IS_MANAGER (self)); + singleton_instance = self; - priv = NM_MANAGER_GET_PRIVATE (singleton); + nm_singleton_instance_register (); + nm_log_dbg (LOGD_CORE, "setup %s singleton (%p)", "NMManager", singleton_instance); - dbus_connection = nm_dbus_manager_get_dbus_connection (priv->dbus_mgr); - if (dbus_connection) { - gboolean success; + nm_exported_object_export ((NMExportedObject *) self); - /* Only fails on ENOMEM */ - success = dbus_connection_add_filter (dbus_connection, prop_filter, singleton, NULL); - g_assert (success); - } + return self; +} - priv->policy = nm_policy_new (singleton, settings); +static void +constructed (GObject *object) +{ + NMManager *self = NM_MANAGER (object); + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + NMConfigData *config_data; + + G_OBJECT_CLASS (nm_manager_parent_class)->constructed (object); + + _set_prop_filter (self, nm_bus_manager_get_connection (priv->dbus_mgr)); + + priv->settings = nm_settings_new (); + g_signal_connect (priv->settings, "notify::" NM_SETTINGS_STARTUP_COMPLETE, + G_CALLBACK (settings_startup_complete_changed), self); + g_signal_connect (priv->settings, "notify::" NM_SETTINGS_UNMANAGED_SPECS, + G_CALLBACK (system_unmanaged_devices_changed_cb), self); + g_signal_connect (priv->settings, "notify::" NM_SETTINGS_HOSTNAME, + G_CALLBACK (system_hostname_changed_cb), self); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED, + G_CALLBACK (connection_changed), self); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED_BY_USER, + G_CALLBACK (connection_changed), self); + g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, + G_CALLBACK (connection_removed), self); + + priv->policy = nm_policy_new (self, priv->settings); g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP4_DEVICE, - G_CALLBACK (policy_default_device_changed), singleton); + G_CALLBACK (policy_default_device_changed), self); g_signal_connect (priv->policy, "notify::" NM_POLICY_DEFAULT_IP6_DEVICE, - G_CALLBACK (policy_default_device_changed), singleton); + G_CALLBACK (policy_default_device_changed), self); g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP4_DEVICE, - G_CALLBACK (policy_activating_device_changed), singleton); + G_CALLBACK (policy_activating_device_changed), self); g_signal_connect (priv->policy, "notify::" NM_POLICY_ACTIVATING_IP6_DEVICE, - G_CALLBACK (policy_activating_device_changed), singleton); + G_CALLBACK (policy_activating_device_changed), self); priv->config = g_object_ref (nm_config_get ()); g_signal_connect (G_OBJECT (priv->config), NM_CONFIG_SIGNAL_CONFIG_CHANGED, G_CALLBACK (_config_changed_cb), - singleton); + self); config_data = nm_config_get_data (priv->config); priv->connectivity = nm_connectivity_new (nm_config_data_get_connectivity_uri (config_data), nm_config_data_get_connectivity_interval (config_data), nm_config_data_get_connectivity_response (config_data)); g_signal_connect (priv->connectivity, "notify::" NM_CONNECTIVITY_STATE, - G_CALLBACK (connectivity_changed), singleton); - - priv->settings = g_object_ref (settings); - g_signal_connect (priv->settings, "notify::" NM_SETTINGS_STARTUP_COMPLETE, - G_CALLBACK (settings_startup_complete_changed), singleton); - - priv->state_file = g_strdup (state_file); - - priv->net_enabled = initial_net_enabled; - - priv->radio_states[RFKILL_TYPE_WLAN].user_enabled = initial_wifi_enabled; - priv->radio_states[RFKILL_TYPE_WWAN].user_enabled = initial_wwan_enabled; - priv->radio_states[RFKILL_TYPE_WIMAX].user_enabled = initial_wimax_enabled; - - g_signal_connect (priv->settings, "notify::" NM_SETTINGS_UNMANAGED_SPECS, - G_CALLBACK (system_unmanaged_devices_changed_cb), singleton); - g_signal_connect (priv->settings, "notify::" NM_SETTINGS_HOSTNAME, - G_CALLBACK (system_hostname_changed_cb), singleton); - g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_ADDED, - G_CALLBACK (connection_added), singleton); - g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, - G_CALLBACK (connection_changed), singleton); - g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, - G_CALLBACK (connection_removed), singleton); - g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, - G_CALLBACK (connection_changed), singleton); - - nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH, singleton); - - g_signal_connect (nm_platform_get (), - NM_PLATFORM_SIGNAL_LINK_CHANGED, - G_CALLBACK (platform_link_cb), - singleton); + G_CALLBACK (connectivity_changed), self); priv->rfkill_mgr = nm_rfkill_manager_new (); g_signal_connect (priv->rfkill_mgr, "rfkill-changed", G_CALLBACK (rfkill_manager_rfkill_changed_cb), - singleton); + self); /* Force kernel WiFi/WWAN rfkill state to follow NM saved WiFi/WWAN state * in case the BIOS doesn't save rfkill state, and to be consistent with user * changes to the WirelessEnabled/WWANEnabled properties which toggle kernel * rfkill. */ - rfkill_change (priv->radio_states[RFKILL_TYPE_WLAN].desc, RFKILL_TYPE_WLAN, initial_wifi_enabled); - rfkill_change (priv->radio_states[RFKILL_TYPE_WWAN].desc, RFKILL_TYPE_WWAN, initial_wwan_enabled); - - nm_device_factory_manager_load_factories (_register_device_factory, singleton); - - return singleton; + rfkill_change (priv->radio_states[RFKILL_TYPE_WLAN].desc, RFKILL_TYPE_WLAN, priv->radio_states[RFKILL_TYPE_WLAN].user_enabled); + rfkill_change (priv->radio_states[RFKILL_TYPE_WWAN].desc, RFKILL_TYPE_WWAN, priv->radio_states[RFKILL_TYPE_WWAN].user_enabled); } static void nm_manager_init (NMManager *manager) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - DBusGConnection *g_connection; guint i; GFile *file; @@ -4860,13 +5170,6 @@ nm_manager_init (NMManager *manager) priv->radio_states[RFKILL_TYPE_WWAN].desc = "WWAN"; priv->radio_states[RFKILL_TYPE_WWAN].rtype = RFKILL_TYPE_WWAN; - priv->radio_states[RFKILL_TYPE_WIMAX].user_enabled = TRUE; - priv->radio_states[RFKILL_TYPE_WIMAX].key = "WimaxEnabled"; - priv->radio_states[RFKILL_TYPE_WIMAX].prop = NM_MANAGER_WIMAX_ENABLED; - priv->radio_states[RFKILL_TYPE_WIMAX].hw_prop = NM_MANAGER_WIMAX_HARDWARE_ENABLED; - priv->radio_states[RFKILL_TYPE_WIMAX].desc = "WiMAX"; - priv->radio_states[RFKILL_TYPE_WIMAX].rtype = RFKILL_TYPE_WIMAX; - for (i = 0; i < RFKILL_TYPE_MAX; i++) priv->radio_states[i].hw_enabled = TRUE; @@ -4874,39 +5177,12 @@ nm_manager_init (NMManager *manager) priv->state = NM_STATE_DISCONNECTED; priv->startup = TRUE; - priv->dbus_mgr = nm_dbus_manager_get (); + priv->dbus_mgr = g_object_ref (nm_bus_manager_get ()); g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_DBUS_CONNECTION_CHANGED, + NM_BUS_MANAGER_DBUS_CONNECTION_CHANGED, G_CALLBACK (dbus_connection_changed_cb), manager); - priv->vpn_manager = g_object_ref (nm_vpn_manager_get ()); - - g_connection = nm_dbus_manager_get_connection (priv->dbus_mgr); - - /* avahi-autoipd stuff */ - priv->aipd_proxy = dbus_g_proxy_new_for_name (g_connection, - NM_AUTOIP_DBUS_SERVICE, - "/", - NM_AUTOIP_DBUS_IFACE); - if (priv->aipd_proxy) { - dbus_g_object_register_marshaller (g_cclosure_marshal_generic, - G_TYPE_NONE, - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_INVALID); - - dbus_g_proxy_add_signal (priv->aipd_proxy, - "Event", - G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, - G_TYPE_INVALID); - - dbus_g_proxy_connect_signal (priv->aipd_proxy, "Event", - G_CALLBACK (aipd_handle_event), - manager, - NULL); - } else - nm_log_warn (LOGD_AUTOIP4, "could not initialize avahi-autoipd D-Bus proxy"); - /* sleep/wake handling */ priv->sleep_monitor = g_object_ref (nm_sleep_monitor_get ()); g_signal_connect (priv->sleep_monitor, NM_SLEEP_MONITOR_SLEEPING, @@ -4945,15 +5221,20 @@ nm_manager_init (NMManager *manager) priv->metered = NM_METERED_UNKNOWN; } +static gboolean +device_is_real (GObject *device, gpointer user_data) +{ + return nm_device_is_real (NM_DEVICE (device)); +} + static void get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) + GValue *value, GParamSpec *pspec) { NMManager *self = NM_MANAGER (object); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *iter; - GPtrArray *array; - const char *path; + NMConfigData *config_data; + const NMGlobalDnsConfig *dns_config; const char *type; switch (prop_id) { @@ -4983,34 +5264,33 @@ get_property (GObject *object, guint prop_id, g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WWAN].hw_enabled); break; case PROP_WIMAX_ENABLED: - g_value_set_boolean (value, radio_enabled_for_type (self, RFKILL_TYPE_WIMAX, TRUE)); + g_value_set_boolean (value, FALSE); break; case PROP_WIMAX_HARDWARE_ENABLED: - g_value_set_boolean (value, priv->radio_states[RFKILL_TYPE_WIMAX].hw_enabled); + g_value_set_boolean (value, FALSE); break; case PROP_ACTIVE_CONNECTIONS: - array = g_ptr_array_sized_new (3); - for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) { - path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (iter->data)); - if (path) - g_ptr_array_add (array, g_strdup (path)); - } - g_value_take_boxed (value, array); + nm_utils_g_value_set_object_path_array (value, priv->active_connections, NULL, NULL); break; case PROP_CONNECTIVITY: g_value_set_uint (value, nm_connectivity_get_state (priv->connectivity)); break; case PROP_PRIMARY_CONNECTION: - path = priv->primary_connection ? nm_active_connection_get_path (priv->primary_connection) : NULL; - g_value_set_boxed (value, path ? path : "/"); + nm_utils_g_value_set_object_path (value, priv->primary_connection); break; case PROP_PRIMARY_CONNECTION_TYPE: - type = priv->primary_connection ? nm_active_connection_get_connection_type (priv->primary_connection) : NULL; + type = NULL; + if (priv->primary_connection) { + NMConnection *con; + + con = nm_active_connection_get_applied_connection (priv->primary_connection); + if (con) + type = nm_connection_get_connection_type (con); + } g_value_set_string (value, type ? type : ""); break; case PROP_ACTIVATING_CONNECTION: - path = priv->activating_connection ? nm_active_connection_get_path (priv->activating_connection) : NULL; - g_value_set_boxed (value, path ? path : "/"); + nm_utils_g_value_set_object_path (value, priv->activating_connection); break; case PROP_HOSTNAME: g_value_set_string (value, priv->hostname); @@ -5019,17 +5299,19 @@ get_property (GObject *object, guint prop_id, g_value_set_boolean (value, priv->sleeping); break; case PROP_DEVICES: - array = g_ptr_array_sized_new (5); - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - path = nm_device_get_path (NM_DEVICE (iter->data)); - if (path) - g_ptr_array_add (array, g_strdup (path)); - } - g_value_take_boxed (value, array); + nm_utils_g_value_set_object_path_array (value, priv->devices, device_is_real, NULL); break; case PROP_METERED: g_value_set_uint (value, priv->metered); break; + case PROP_GLOBAL_DNS_CONFIGURATION: + config_data = nm_config_get_data (priv->config); + dns_config = nm_config_data_get_global_dns_config (config_data); + nm_global_dns_config_to_dbus (dns_config, value); + break; + case PROP_ALL_DEVICES: + nm_utils_g_value_set_object_path_array (value, priv->devices, NULL, NULL); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -5038,30 +5320,56 @@ get_property (GObject *object, guint prop_id, static void set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) + const GValue *value, GParamSpec *pspec) { NMManager *self = NM_MANAGER (object); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + NMGlobalDnsConfig *dns_config; + GError *error = NULL; switch (prop_id) { + case PROP_STATE_FILE: + /* construct-only */ + priv->state_file = g_value_dup_string (value); + break; case PROP_NETWORKING_ENABLED: - /* Construct only for now */ + /* construct-only */ priv->net_enabled = g_value_get_boolean (value); break; case PROP_WIRELESS_ENABLED: - manager_radio_user_toggled (NM_MANAGER (object), - &priv->radio_states[RFKILL_TYPE_WLAN], - g_value_get_boolean (value)); + if (!priv->rfkill_mgr) { + /* called during object construction. */ + priv->radio_states[RFKILL_TYPE_WLAN].user_enabled = g_value_get_boolean (value); + } else { + manager_radio_user_toggled (NM_MANAGER (object), + &priv->radio_states[RFKILL_TYPE_WLAN], + g_value_get_boolean (value)); + } break; case PROP_WWAN_ENABLED: - manager_radio_user_toggled (NM_MANAGER (object), - &priv->radio_states[RFKILL_TYPE_WWAN], - g_value_get_boolean (value)); + if (!priv->rfkill_mgr) { + /* called during object construction. */ + priv->radio_states[RFKILL_TYPE_WWAN].user_enabled = g_value_get_boolean (value); + } else { + manager_radio_user_toggled (NM_MANAGER (object), + &priv->radio_states[RFKILL_TYPE_WWAN], + g_value_get_boolean (value)); + } break; case PROP_WIMAX_ENABLED: - manager_radio_user_toggled (NM_MANAGER (object), - &priv->radio_states[RFKILL_TYPE_WIMAX], - g_value_get_boolean (value)); + /* WIMAX is depreacted. This does nothing. */ + break; + case PROP_GLOBAL_DNS_CONFIGURATION: + dns_config = nm_global_dns_config_from_dbus (value, &error); + if (!error) + nm_config_set_global_dns (priv->config, dns_config, &error); + + nm_global_dns_config_free (dns_config); + + if (error) { + nm_log_dbg (LOGD_CORE, "set global DNS failed with error: %s", error->message); + g_error_free (error); + } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -5080,7 +5388,6 @@ dispose (GObject *object) { NMManager *manager = NM_MANAGER (object); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - DBusConnection *dbus_connection; g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_unref); priv->auth_chains = NULL; @@ -5091,10 +5398,7 @@ dispose (GObject *object) g_assert (priv->devices == NULL); - if (priv->ac_cleanup_id) { - g_source_remove (priv->ac_cleanup_id); - priv->ac_cleanup_id = 0; - } + nm_clear_g_source (&priv->ac_cleanup_id); while (priv->active_connections) active_connection_remove (manager, NM_ACTIVE_CONNECTION (priv->active_connections->data)); @@ -5123,25 +5427,21 @@ dispose (GObject *object) g_signal_handlers_disconnect_by_func (priv->settings, settings_startup_complete_changed, manager); g_signal_handlers_disconnect_by_func (priv->settings, system_unmanaged_devices_changed_cb, manager); g_signal_handlers_disconnect_by_func (priv->settings, system_hostname_changed_cb, manager); - g_signal_handlers_disconnect_by_func (priv->settings, connection_added, manager); g_signal_handlers_disconnect_by_func (priv->settings, connection_changed, manager); g_signal_handlers_disconnect_by_func (priv->settings, connection_removed, manager); g_clear_object (&priv->settings); } - g_free (priv->state_file); + g_clear_pointer (&priv->state_file, g_free); g_clear_object (&priv->vpn_manager); /* Unregister property filter */ if (priv->dbus_mgr) { - dbus_connection = nm_dbus_manager_get_dbus_connection (priv->dbus_mgr); - if (dbus_connection) - dbus_connection_remove_filter (dbus_connection, prop_filter, manager); g_signal_handlers_disconnect_by_func (priv->dbus_mgr, dbus_connection_changed_cb, manager); - priv->dbus_mgr = NULL; + g_clear_object (&priv->dbus_mgr); } + _set_prop_filter (manager, NULL); - g_clear_object (&priv->aipd_proxy); if (priv->sleep_monitor) { g_signal_handlers_disconnect_by_func (priv->sleep_monitor, sleeping_cb, manager); g_signal_handlers_disconnect_by_func (priv->sleep_monitor, resuming_cb, manager); @@ -5151,10 +5451,7 @@ dispose (GObject *object) if (priv->fw_monitor) { g_signal_handlers_disconnect_by_func (priv->fw_monitor, firmware_dir_changed, manager); - if (priv->fw_changed_id) { - g_source_remove (priv->fw_changed_id); - priv->fw_changed_id = 0; - } + nm_clear_g_source (&priv->fw_changed_id); g_file_monitor_cancel (priv->fw_monitor); g_clear_object (&priv->fw_monitor); @@ -5166,11 +5463,8 @@ dispose (GObject *object) } nm_device_factory_manager_for_each_factory (_deinit_device_factory, manager); - - if (priv->timestamp_update_id) { - g_source_remove (priv->timestamp_update_id); - priv->timestamp_update_id = 0; - } + + nm_clear_g_source (&priv->timestamp_update_id); G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object); } @@ -5179,10 +5473,14 @@ static void nm_manager_class_init (NMManagerClass *manager_class) { GObjectClass *object_class = G_OBJECT_CLASS (manager_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (manager_class); g_type_class_add_private (manager_class, sizeof (NMManagerPrivate)); + exported_object_class->export_path = NM_DBUS_PATH; + /* virtual methods */ + object_class->constructed = constructed; object_class->set_property = set_property; object_class->get_property = get_property; object_class->dispose = dispose; @@ -5195,6 +5493,14 @@ nm_manager_class_init (NMManagerClass *manager_class) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, + PROP_STATE_FILE, + g_param_spec_string (NM_MANAGER_STATE_FILE, "", "", + NULL, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (object_class, PROP_STATE, g_param_spec_uint (NM_MANAGER_STATE, "", "", @@ -5221,6 +5527,7 @@ nm_manager_class_init (NMManagerClass *manager_class) g_param_spec_boolean (NM_MANAGER_WIRELESS_ENABLED, "", "", TRUE, G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); g_object_class_install_property @@ -5235,6 +5542,7 @@ nm_manager_class_init (NMManagerClass *manager_class) g_param_spec_boolean (NM_MANAGER_WWAN_ENABLED, "", "", TRUE, G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); g_object_class_install_property @@ -5261,7 +5569,7 @@ nm_manager_class_init (NMManagerClass *manager_class) g_object_class_install_property (object_class, PROP_ACTIVE_CONNECTIONS, g_param_spec_boxed (NM_MANAGER_ACTIVE_CONNECTIONS, "", "", - DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, + G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -5274,10 +5582,10 @@ nm_manager_class_init (NMManagerClass *manager_class) g_object_class_install_property (object_class, PROP_PRIMARY_CONNECTION, - g_param_spec_boxed (NM_MANAGER_PRIMARY_CONNECTION, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_MANAGER_PRIMARY_CONNECTION, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); g_object_class_install_property (object_class, PROP_PRIMARY_CONNECTION_TYPE, @@ -5289,10 +5597,10 @@ nm_manager_class_init (NMManagerClass *manager_class) g_object_class_install_property (object_class, PROP_ACTIVATING_CONNECTION, - g_param_spec_boxed (NM_MANAGER_ACTIVATING_CONNECTION, "", "", - DBUS_TYPE_G_OBJECT_PATH, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); + g_param_spec_string (NM_MANAGER_ACTIVATING_CONNECTION, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); /* Hostname is not exported over D-Bus */ g_object_class_install_property @@ -5313,7 +5621,7 @@ nm_manager_class_init (NMManagerClass *manager_class) g_object_class_install_property (object_class, PROP_DEVICES, g_param_spec_boxed (NM_MANAGER_DEVICES, "", "", - DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, + G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -5322,7 +5630,7 @@ nm_manager_class_init (NMManagerClass *manager_class) * * Whether the connectivity is metered. * - * Since: 1.0.6 + * Since: 1.2 **/ g_object_class_install_property (object_class, PROP_METERED, @@ -5331,25 +5639,73 @@ nm_manager_class_init (NMManagerClass *manager_class) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + /** + * NMManager:global-dns-configuration: + * + * The global DNS configuration. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_GLOBAL_DNS_CONFIGURATION, + g_param_spec_variant (NM_MANAGER_GLOBAL_DNS_CONFIGURATION, "", "", + G_VARIANT_TYPE ("a{sv}"), + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMManager:all-devices: + * + * All devices, including those that are not realized. + * + * Since: 1.2 + **/ + g_object_class_install_property + (object_class, PROP_ALL_DEVICES, + g_param_spec_boxed (NM_MANAGER_ALL_DEVICES, "", "", + G_TYPE_STRV, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + /* signals */ + + /* D-Bus exported; emitted only for realized devices */ signals[DEVICE_ADDED] = g_signal_new ("device-added", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMManagerClass, device_added), NULL, NULL, NULL, + G_TYPE_NONE, 1, NM_TYPE_DEVICE); + + /* Emitted for both realized devices and placeholder devices */ + signals[INTERNAL_DEVICE_ADDED] = + g_signal_new ("internal-device-added", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, 0, + NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_OBJECT); + /* D-Bus exported; emitted only for realized devices */ signals[DEVICE_REMOVED] = g_signal_new ("device-removed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMManagerClass, device_removed), NULL, NULL, NULL, + G_TYPE_NONE, 1, NM_TYPE_DEVICE); + + /* Emitted for both realized devices and placeholder devices */ + signals[INTERNAL_DEVICE_REMOVED] = + g_signal_new ("internal-device-removed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, 0, + NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_OBJECT); signals[STATE_CHANGED] = - g_signal_new ("state-changed", + g_signal_new (NM_MANAGER_STATE_CHANGED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMManagerClass, state_changed), @@ -5375,14 +5731,14 @@ nm_manager_class_init (NMManagerClass *manager_class) G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_OBJECT); + G_TYPE_NONE, 1, NM_TYPE_ACTIVE_CONNECTION); signals[ACTIVE_CONNECTION_REMOVED] = g_signal_new (NM_MANAGER_ACTIVE_CONNECTION_REMOVED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_OBJECT); + G_TYPE_NONE, 1, NM_TYPE_ACTIVE_CONNECTION); signals[CONFIGURE_QUIT] = g_signal_new (NM_MANAGER_CONFIGURE_QUIT, @@ -5391,10 +5747,21 @@ nm_manager_class_init (NMManagerClass *manager_class) 0, NULL, NULL, NULL, G_TYPE_NONE, 0); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (manager_class), - &dbus_glib_nm_manager_object_info); - - dbus_g_error_domain_register (NM_MANAGER_ERROR, NM_DBUS_INTERFACE, NM_TYPE_MANAGER_ERROR); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (manager_class), + NMDBUS_TYPE_MANAGER_SKELETON, + "GetDevices", impl_manager_get_devices, + "GetAllDevices", impl_manager_get_all_devices, + "GetDeviceByIpIface", impl_manager_get_device_by_ip_iface, + "ActivateConnection", impl_manager_activate_connection, + "AddAndActivateConnection", impl_manager_add_and_activate_connection, + "DeactivateConnection", impl_manager_deactivate_connection, + "Sleep", impl_manager_sleep, + "Enable", impl_manager_enable, + "GetPermissions", impl_manager_get_permissions, + "SetLogging", impl_manager_set_logging, + "GetLogging", impl_manager_get_logging, + "CheckConnectivity", impl_manager_check_connectivity, + "state", impl_manager_get_state, + NULL); } diff --git a/src/nm-manager.h b/src/nm-manager.h index 711bcce8..2935d2a2 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -22,11 +22,8 @@ #ifndef __NETWORKMANAGER_MANAGER_H__ #define __NETWORKMANAGER_MANAGER_H__ -#include -#include - -#include "nm-types.h" -#include "nm-connection.h" +#include "nm-exported-object.h" +#include "nm-settings-connection.h" #define NM_TYPE_MANAGER (nm_manager_get_type ()) #define NM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MANAGER, NMManager)) @@ -52,23 +49,27 @@ #define NM_MANAGER_ACTIVATING_CONNECTION "activating-connection" #define NM_MANAGER_DEVICES "devices" #define NM_MANAGER_METERED "metered" +#define NM_MANAGER_GLOBAL_DNS_CONFIGURATION "global-dns-configuration" +#define NM_MANAGER_ALL_DEVICES "all-devices" /* Not exported */ #define NM_MANAGER_HOSTNAME "hostname" #define NM_MANAGER_SLEEPING "sleeping" +#define NM_MANAGER_STATE_FILE "state-file" /* Internal signals */ #define NM_MANAGER_ACTIVE_CONNECTION_ADDED "active-connection-added" #define NM_MANAGER_ACTIVE_CONNECTION_REMOVED "active-connection-removed" #define NM_MANAGER_CONFIGURE_QUIT "configure-quit" +#define NM_MANAGER_STATE_CHANGED "state-changed" struct _NMManager { - GObject parent; + NMExportedObject parent; }; typedef struct { - GObjectClass parent; + NMExportedObjectClass parent; /* Signals */ void (*device_added) (NMManager *manager, NMDevice *device); @@ -78,17 +79,16 @@ typedef struct { GType nm_manager_get_type (void); -/* nm_manager_new() should only be used by main.c */ -NMManager * nm_manager_new (NMSettings *settings, - const char *state_file, +/* nm_manager_setup() should only be used by main.c */ +NMManager * nm_manager_setup (const char *state_file, gboolean initial_net_enabled, gboolean initial_wifi_enabled, - gboolean initial_wwan_enabled, - gboolean initial_wimax_enabled); + gboolean initial_wwan_enabled); NMManager * nm_manager_get (void); -void nm_manager_start (NMManager *manager); +gboolean nm_manager_start (NMManager *manager, + GError **error); void nm_manager_stop (NMManager *manager); NMState nm_manager_get_state (NMManager *manager); const GSList *nm_manager_get_active_connections (NMManager *manager); @@ -102,7 +102,7 @@ NMDevice * nm_manager_get_device_by_ifindex (NMManager *manager, int ifindex); NMActiveConnection *nm_manager_activate_connection (NMManager *manager, - NMConnection *connection, + NMSettingsConnection *connection, const char *specific_object, NMDevice *device, NMAuthSubject *subject, diff --git a/src/nm-multi-index.c b/src/nm-multi-index.c index d45f4834..47cd9810 100644 --- a/src/nm-multi-index.c +++ b/src/nm-multi-index.c @@ -20,14 +20,13 @@ #include "config.h" +#include "nm-default.h" #include "nm-multi-index.h" #include -#include "nm-glib-compat.h" #include "nm-macros-internal.h" - struct NMMultiIndex { NMMultiIndexFuncEqual equal_fcn; NMMultiIndexFuncClone clone_fcn; @@ -35,56 +34,72 @@ struct NMMultiIndex { }; typedef struct { + /* when storing the first item for a multi-index id, we don't yet create + * the hashtable @index. Instead we store it inplace to @value0. Note that + * &values_data->value0 is a NULL terminated array with one item that is + * suitable to be returned directly from nm_multi_index_lookup(). */ + union { + gpointer value0; + gpointer *values; + }; GHashTable *index; - gpointer *values; } ValuesData; /******************************************************************************************/ -static ValuesData * -_values_data_create (void) -{ - ValuesData *values_data; - - values_data = g_slice_new (ValuesData); - values_data->index = g_hash_table_new (NULL, NULL); - values_data->values = NULL; - return values_data; -} - static void _values_data_destroy (ValuesData *values_data) { - if (values_data) { + if (values_data->index) { g_free (values_data->values); g_hash_table_unref (values_data->index); - g_slice_free (ValuesData, values_data); } + g_slice_free (ValuesData, values_data); +} + +static gboolean +_values_data_contains (ValuesData *values_data, gconstpointer value) +{ + return values_data->index + ? g_hash_table_contains (values_data->index, value) + : value == values_data->value0; } static void -_values_data_populate_array (ValuesData *values_data) +_values_data_get_data (ValuesData *values_data, + void *const**out_data, + guint *out_len) { guint i, len; gpointer *values; GHashTableIter iter; nm_assert (values_data); - nm_assert (values_data->index && g_hash_table_size (values_data->index) > 0); - if (values_data->values) + if (!values_data->index) { + NM_SET_OUT (out_data, &values_data->value0); + NM_SET_OUT (out_len, 1); return; + } + + nm_assert (values_data->index && g_hash_table_size (values_data->index) > 0); + + if (!values_data->values) { + len = g_hash_table_size (values_data->index); + values = g_new (gpointer, len + 1); - len = g_hash_table_size (values_data->index); - values = g_new (gpointer, len + 1); + g_hash_table_iter_init (&iter, values_data->index); + for (i = 0; g_hash_table_iter_next (&iter, &values[i], NULL); i++) + nm_assert (i < len); + nm_assert (i == len); + values[i] = NULL; - g_hash_table_iter_init (&iter, values_data->index); - for (i = 0; g_hash_table_iter_next (&iter, &values[i], NULL); i++) - nm_assert (i < len); - nm_assert (i == len); - values[i] = NULL; + values_data->values = values; + NM_SET_OUT (out_len, len); + } else if (out_len) + NM_SET_OUT (out_len, g_hash_table_size (values_data->index)); - values_data->values = values; + NM_SET_OUT (out_data, values_data->values); } /******************************************************************************************/ @@ -105,6 +120,7 @@ nm_multi_index_lookup (const NMMultiIndex *index, guint *out_len) { ValuesData *values_data; + void *const*values; g_return_val_if_fail (index, NULL); g_return_val_if_fail (id, NULL); @@ -115,10 +131,8 @@ nm_multi_index_lookup (const NMMultiIndex *index, *out_len = 0; return NULL; } - _values_data_populate_array (values_data); - if (out_len) - *out_len = g_hash_table_size (values_data->index); - return values_data->values; + _values_data_get_data (values_data, &values, out_len); + return values; } gboolean @@ -133,8 +147,7 @@ nm_multi_index_contains (const NMMultiIndex *index, g_return_val_if_fail (value, FALSE); values_data = g_hash_table_lookup (index->hash, id); - return values_data - && g_hash_table_contains (values_data->index, value); + return values_data && _values_data_contains (values_data, value); } const NMMultiIndexId * @@ -158,7 +171,7 @@ nm_multi_index_lookup_first_by_value (const NMMultiIndex *index, g_hash_table_iter_init (&iter, index->hash); while (g_hash_table_iter_next (&iter, (gpointer *) &id, (gpointer *) &values_data)) { - if (g_hash_table_contains (values_data->index, value)) + if (_values_data_contains (values_data, value)) return id; } return NULL; @@ -173,18 +186,19 @@ nm_multi_index_foreach (const NMMultiIndex *index, GHashTableIter iter; const NMMultiIndexId *id; ValuesData *values_data; + guint len; + void *const*values; g_return_if_fail (index); g_return_if_fail (foreach_func); g_hash_table_iter_init (&iter, index->hash); while (g_hash_table_iter_next (&iter, (gpointer *) &id, (gpointer *) &values_data)) { - if ( value - && !g_hash_table_contains (values_data->index, value)) + if (value && !_values_data_contains (values_data, value)) continue; - _values_data_populate_array (values_data); - if (!foreach_func (id, values_data->values, g_hash_table_size (values_data->index), user_data)) + _values_data_get_data (values_data, &values, &len); + if (!foreach_func (id, values, len, user_data)) return; } } @@ -215,14 +229,11 @@ nm_multi_index_iter_next (NMMultiIndexIter *iter, while (g_hash_table_iter_next (&iter->_iter, (gpointer *) &id, (gpointer *) &values_data)) { if ( !iter->_value - || g_hash_table_contains (values_data->index, iter->_value)) { - _values_data_populate_array (values_data); + || _values_data_contains (values_data, iter->_value)) { + if (out_values || out_len) + _values_data_get_data (values_data, out_values, out_len); if (out_id) *out_id = id; - if (out_values) - *out_values = values_data->values; - if (out_len) - *out_len = g_hash_table_size (values_data->index); return TRUE; } } @@ -244,10 +255,13 @@ nm_multi_index_id_iter_init (NMMultiIndexIdIter *iter, values_data = g_hash_table_lookup (index->hash, id); if (!values_data) + iter->_state = 2; + else if (values_data->index) { iter->_state = 1; - else { - iter->_state = 0; g_hash_table_iter_init (&iter->_iter, values_data->index); + } else { + iter->_state = 0; + iter->_value = values_data->value0; } } @@ -256,13 +270,19 @@ nm_multi_index_id_iter_next (NMMultiIndexIdIter *iter, void **out_value) { g_return_val_if_fail (iter, FALSE); - g_return_val_if_fail (iter->_state <= 1, FALSE); - if (iter->_state == 0) - return g_hash_table_iter_next (&iter->_iter, out_value, NULL); - else { + switch (iter->_state) { + case 0: iter->_state = 2; + NM_SET_OUT (out_value, iter->_value); + return TRUE; + case 1: + return g_hash_table_iter_next (&iter->_iter, out_value, NULL); + case 2: + iter->_state = 3; return FALSE; + default: + g_return_val_if_reached (FALSE); } } @@ -292,14 +312,23 @@ _do_add (NMMultiIndex *index, if (!id_new) g_return_val_if_reached (FALSE); - values_data = _values_data_create (); - g_hash_table_replace (values_data->index, (gpointer) value, (gpointer) value); + values_data = g_slice_new0 (ValuesData); + values_data->value0 = (gpointer) value; g_hash_table_insert (index->hash, id_new, values_data); } else { - if (!nm_g_hash_table_replace (values_data->index, (gpointer) value, (gpointer) value)) - return FALSE; - g_clear_pointer (&values_data->values, g_free); + if (!values_data->index) { + if (values_data->value0 == value) + return FALSE; + values_data->index = g_hash_table_new (NULL, NULL); + g_hash_table_replace (values_data->index, (gpointer) value, (gpointer) value); + g_hash_table_replace (values_data->index, values_data->value0, values_data->value0); + values_data->values = NULL; + } else { + if (!nm_g_hash_table_replace (values_data->index, (gpointer) value, (gpointer) value)) + return FALSE; + g_clear_pointer (&values_data->values, g_free); + } } return TRUE; } @@ -315,13 +344,19 @@ _do_remove (NMMultiIndex *index, if (!values_data) return FALSE; - if (!g_hash_table_remove (values_data->index, value)) - return FALSE; - - if (g_hash_table_size (values_data->index) == 0) + if (values_data->index) { + if (!g_hash_table_remove (values_data->index, value)) + return FALSE; + if (g_hash_table_size (values_data->index) == 0) + g_hash_table_remove (index->hash, id); + else + g_clear_pointer (&values_data->values, g_free); + } else { + if (values_data->value0 != value) + return FALSE; g_hash_table_remove (index->hash, id); - else - g_clear_pointer (&values_data->values, g_free); + } + return TRUE; } diff --git a/src/nm-multi-index.h b/src/nm-multi-index.h index e41ef54e..1e1e8fda 100644 --- a/src/nm-multi-index.h +++ b/src/nm-multi-index.h @@ -21,7 +21,7 @@ #ifndef __NM_MULTI_INDEX__ #define __NM_MULTI_INDEX__ -#include +#include "nm-default.h" G_BEGIN_DECLS @@ -39,7 +39,10 @@ typedef struct { } NMMultiIndexIter; typedef struct { - GHashTableIter _iter; + union { + GHashTableIter _iter; + gpointer _value; + }; guint _state; } NMMultiIndexIdIter; diff --git a/src/nm-policy.c b/src/nm-policy.c index fc2a9bf7..05f7edf4 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -26,15 +26,13 @@ #include #include -#include +#include "nm-default.h" #include "nm-policy.h" #include "NetworkManagerUtils.h" #include "nm-activation-request.h" -#include "nm-logging.h" #include "nm-device.h" #include "nm-default-route-manager.h" -#include "nm-dbus-manager.h" #include "nm-setting-ip4-config.h" #include "nm-setting-connection.h" #include "nm-platform.h" @@ -45,7 +43,6 @@ #include "nm-dispatcher.h" #include "nm-utils.h" #include "nm-core-internal.h" -#include "nm-glib-compat.h" #include "nm-manager.h" #include "nm-settings.h" #include "nm-settings-connection.h" @@ -54,6 +51,7 @@ typedef struct { NMManager *manager; + NMFirewallManager *firewall_manager; guint update_state_id; GSList *pending_activation_checks; GSList *manager_ids; @@ -75,7 +73,7 @@ typedef struct { NMDnsManager *dns_manager; gulong config_changed_id; - gint reset_retries_id; /* idle handler for resetting the retries count */ + guint reset_retries_id; /* idle handler for resetting the retries count */ char *orig_hostname; /* hostname at NM start time */ char *cur_hostname; /* hostname we want to assign */ @@ -150,8 +148,12 @@ set_system_hostname (const char *new_hostname, const char *msg) nm_log_info (LOGD_DNS, "Setting system hostname to '%s' (%s)", name, msg); ret = sethostname (name, strlen (name)); if (ret != 0) { + int errsv = errno; + nm_log_warn (LOGD_DNS, "couldn't set the system hostname to '%s': (%d) %s", - name, errno, strerror (errno)); + name, errsv, strerror (errsv)); + if (errsv == EPERM) + nm_log_warn (LOGD_DNS, "You should use hostnamed when systemd hardening is in effect!"); } return (ret == 0); @@ -197,7 +199,7 @@ _set_hostname (NMPolicy *policy, nm_dns_manager_set_hostname (priv->dns_manager, priv->cur_hostname); if (set_system_hostname (priv->cur_hostname, msg)) - nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL, NULL); + nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL, NULL, NULL); } static void @@ -468,7 +470,7 @@ update_ip4_routing (NMPolicy *policy, gboolean force_update) return; priv->default_device4 = default_device; - connection = nm_active_connection_get_connection (best_ac); + connection = nm_active_connection_get_applied_connection (best_ac); nm_log_info (LOGD_CORE, "Policy set '%s' (%s) as default for IPv4 routing and DNS.", nm_connection_get_id (connection), ip_iface); g_object_notify (G_OBJECT (policy), NM_POLICY_DEFAULT_IP4_DEVICE); @@ -563,7 +565,7 @@ update_ip6_routing (NMPolicy *policy, gboolean force_update) return; priv->default_device6 = default_device6; - connection = nm_active_connection_get_connection (best_ac); + connection = nm_active_connection_get_applied_connection (best_ac); nm_log_info (LOGD_CORE, "Policy set '%s' (%s) as default for IPv6 routing and DNS.", nm_connection_get_id (connection), ip_iface); g_object_notify (G_OBJECT (policy), NM_POLICY_DEFAULT_IP6_DEVICE); @@ -638,7 +640,7 @@ auto_activate_device (gpointer user_data) ActivateData *data = (ActivateData *) user_data; NMPolicy *policy; NMPolicyPrivate *priv; - NMConnection *best_connection; + NMSettingsConnection *best_connection; char *specific_object = NULL; GPtrArray *connections; GSList *connection_list; @@ -676,7 +678,7 @@ auto_activate_device (gpointer user_data) if (!nm_settings_connection_can_autoconnect (candidate)) continue; if (nm_device_can_auto_connect (data->device, (NMConnection *) candidate, &specific_object)) { - best_connection = (NMConnection *) candidate; + best_connection = candidate; break; } } @@ -687,7 +689,7 @@ auto_activate_device (gpointer user_data) NMAuthSubject *subject; nm_log_info (LOGD_DEVICE, "Auto-activating connection '%s'.", - nm_connection_get_id (best_connection)); + nm_settings_connection_get_id (best_connection)); subject = nm_auth_subject_new_internal (); if (!nm_manager_activate_connection (priv->manager, best_connection, @@ -696,7 +698,7 @@ auto_activate_device (gpointer user_data) subject, &error)) { nm_log_info (LOGD_DEVICE, "Connection '%s' auto-activation failed: (%d) %s", - nm_connection_get_id (best_connection), + nm_settings_connection_get_id (best_connection), error ? error->code : -1, error ? error->message : "(none)"); g_error_free (error); @@ -774,8 +776,8 @@ process_secondaries (NMPolicy *policy, if (connected) { nm_log_dbg (LOGD_DEVICE, "Secondary connection '%s' SUCCEEDED; active path '%s'", - nm_active_connection_get_id (active), - nm_active_connection_get_path (active)); + nm_active_connection_get_settings_connection_id (active), + nm_exported_object_get_path (NM_EXPORTED_OBJECT (active))); /* Secondary connection activated */ secondary_data->secondaries = g_slist_remove (secondary_data->secondaries, secondary_active); @@ -790,8 +792,8 @@ process_secondaries (NMPolicy *policy, } } else { nm_log_dbg (LOGD_DEVICE, "Secondary connection '%s' FAILED; active path '%s'", - nm_active_connection_get_id (active), - nm_active_connection_get_path (active)); + nm_active_connection_get_settings_connection_id (active), + nm_exported_object_get_path (NM_EXPORTED_OBJECT (active))); /* Secondary connection failed -> do not watch other connections */ priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data); @@ -989,7 +991,7 @@ static void activate_slave_connections (NMPolicy *policy, NMDevice *device) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - const char *master_device, *master_uuid = NULL; + const char *master_device, *master_uuid_settings = NULL, *master_uuid_applied = NULL; GSList *connections, *iter; NMActRequest *req; @@ -997,8 +999,19 @@ activate_slave_connections (NMPolicy *policy, NMDevice *device) g_assert (master_device); req = nm_device_get_act_request (device); - if (req) - master_uuid = nm_active_connection_get_uuid (NM_ACTIVE_CONNECTION (req)); + if (req) { + NMConnection *con; + + con = nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (req)); + if (con) + master_uuid_applied = nm_connection_get_uuid (con); + con = NM_CONNECTION (nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (req))); + if (con) { + master_uuid_settings = nm_connection_get_uuid (con); + if (!g_strcmp0 (master_uuid_settings, master_uuid_applied)) + master_uuid_settings = NULL; + } + } connections = nm_settings_get_connections (priv->settings); for (iter = connections; iter; iter = g_slist_next (iter)) { @@ -1015,7 +1028,9 @@ activate_slave_connections (NMPolicy *policy, NMDevice *device) if (!slave_master) continue; - if (!g_strcmp0 (slave_master, master_device) || !g_strcmp0 (slave_master, master_uuid)) + if ( !g_strcmp0 (slave_master, master_device) + || !g_strcmp0 (slave_master, master_uuid_applied) + || !g_strcmp0 (slave_master, master_uuid_settings)) nm_settings_connection_reset_autoconnect_retries (NM_SETTINGS_CONNECTION (slave)); } @@ -1055,7 +1070,7 @@ activate_secondary_connections (NMPolicy *policy, } if (!nm_connection_is_type (NM_CONNECTION (settings_con), NM_SETTING_VPN_SETTING_NAME)) { nm_log_warn (LOGD_DEVICE, "Secondary connection '%s (%s)' auto-activation failed: The connection is not a VPN.", - nm_connection_get_id (NM_CONNECTION (settings_con)), sec_uuid); + nm_settings_connection_get_id (settings_con), sec_uuid); success = FALSE; break; } @@ -1064,11 +1079,11 @@ activate_secondary_connections (NMPolicy *policy, g_assert (req); nm_log_dbg (LOGD_DEVICE, "Activating secondary connection '%s (%s)' for base connection '%s (%s)'", - nm_connection_get_id (NM_CONNECTION (settings_con)), sec_uuid, + nm_settings_connection_get_id (settings_con), sec_uuid, nm_connection_get_id (connection), nm_connection_get_uuid (connection)); ac = nm_manager_activate_connection (priv->manager, - NM_CONNECTION (settings_con), - nm_active_connection_get_path (NM_ACTIVE_CONNECTION (req)), + settings_con, + nm_exported_object_get_path (NM_EXPORTED_OBJECT (req)), device, nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (req)), &error); @@ -1076,7 +1091,7 @@ activate_secondary_connections (NMPolicy *policy, secondary_ac_list = g_slist_append (secondary_ac_list, g_object_ref (ac)); else { nm_log_warn (LOGD_DEVICE, "Secondary connection '%s (%s)' auto-activation failed: (%d) %s", - nm_connection_get_id (NM_CONNECTION (settings_con)), sec_uuid, + nm_settings_connection_get_id (settings_con), sec_uuid, error ? error->code : 0, (error && error->message) ? error->message : "unknown"); g_clear_error (&error); @@ -1103,7 +1118,9 @@ device_state_changed (NMDevice *device, { NMPolicy *policy = (NMPolicy *) user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - NMSettingsConnection *connection = NM_SETTINGS_CONNECTION (nm_device_get_connection (device)); + + NMSettingsConnection *connection = nm_device_get_settings_connection (device); + const char *ip_iface = nm_device_get_ip_iface (device); NMIP4Config *ip4_config; NMIP6Config *ip6_config; @@ -1121,18 +1138,18 @@ device_state_changed (NMDevice *device, if (reason == NM_DEVICE_STATE_REASON_NO_SECRETS) { nm_log_dbg (LOGD_DEVICE, "Connection '%s' now blocked from autoconnect due to no secrets", - nm_connection_get_id (NM_CONNECTION (connection))); + nm_settings_connection_get_id (connection)); nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_DEVICE_STATE_REASON_NO_SECRETS); } else if (tries > 0) { nm_log_dbg (LOGD_DEVICE, "Connection '%s' failed to autoconnect; %d tries left", - nm_connection_get_id (NM_CONNECTION (connection)), tries); + nm_settings_connection_get_id (connection), tries); nm_settings_connection_set_autoconnect_retries (connection, tries - 1); } if (nm_settings_connection_get_autoconnect_retries (connection) == 0) { nm_log_info (LOGD_DEVICE, "Disabling autoconnect for connection '%s'.", - nm_connection_get_id (NM_CONNECTION (connection))); + nm_settings_connection_get_id (connection)); /* Schedule a handler to reset retries count */ if (!priv->reset_retries_id) { gint32 retry_time = nm_settings_connection_get_autoconnect_retry_time (connection); @@ -1152,6 +1169,7 @@ device_state_changed (NMDevice *device, /* And clear secrets so they will always be requested from the * settings service when the next connection is made. */ + nm_connection_clear_secrets (NM_CONNECTION (connection)); } @@ -1184,7 +1202,7 @@ device_state_changed (NMDevice *device, if (connection) { /* The connection was deactivated, so block just this connection */ nm_log_dbg (LOGD_DEVICE, "Blocking autoconnect of connection '%s' by user request", - nm_connection_get_id (NM_CONNECTION (connection))); + nm_settings_connection_get_id (connection)); nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_DEVICE_STATE_REASON_USER_REQUESTED); } @@ -1352,7 +1370,7 @@ device_added (NMManager *manager, NMDevice *device, gpointer user_data) NMPolicy *policy = (NMPolicy *) user_data; /* Connect state-changed with _after, so that the handler is invoked after other handlers. */ - _connect_device_signal (policy, device, "state-changed", device_state_changed, TRUE); + _connect_device_signal (policy, device, NM_DEVICE_STATE_CHANGED, device_state_changed, TRUE); _connect_device_signal (policy, device, NM_DEVICE_IP4_CONFIG_CHANGED, device_ip4_config_changed, FALSE); _connect_device_signal (policy, device, NM_DEVICE_IP6_CONFIG_CHANGED, device_ip6_config_changed, FALSE); _connect_device_signal (policy, device, "notify::" NM_DEVICE_AUTOCONNECT, device_autoconnect_changed, FALSE); @@ -1465,7 +1483,7 @@ vpn_connection_retry_after_failure (NMVpnConnection *vpn, NMPolicy *policy) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); NMActiveConnection *ac = NM_ACTIVE_CONNECTION (vpn); - NMConnection *connection = nm_active_connection_get_connection (ac); + NMSettingsConnection *connection = nm_active_connection_get_settings_connection (ac); GError *error = NULL; /* Attempt to reconnect VPN connections that failed after being connected */ @@ -1476,7 +1494,7 @@ vpn_connection_retry_after_failure (NMVpnConnection *vpn, NMPolicy *policy) nm_active_connection_get_subject (ac), &error)) { nm_log_warn (LOGD_DEVICE, "VPN '%s' reconnect failed: %s", - nm_connection_get_id (connection), + nm_settings_connection_get_id (connection), error->message ? error->message : "unknown"); g_clear_error (&error); } @@ -1556,71 +1574,17 @@ connection_added (NMSettings *settings, schedule_activate_all (policy); } -static void -add_or_change_zone_cb (GError *error, gpointer user_data) -{ - NMDevice *device = NM_DEVICE (user_data); - - if (error) { - /* FIXME: what do we do here? */ - } - - g_object_unref (device); -} - -static void -firewall_update_zone (NMPolicy *policy, NMConnection *connection) -{ - NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - NMSettingConnection *s_con = nm_connection_get_setting_connection (connection); - const GSList *iter; - - /* find dev with passed connection and change zone its interface belongs to */ - for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) { - NMDevice *dev = NM_DEVICE (iter->data); - - if ( (nm_device_get_connection (dev) == connection) - && (nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED) - && !nm_device_uses_assumed_connection (dev)) { - nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (), - nm_device_get_ip_iface (dev), - nm_setting_connection_get_zone (s_con), - FALSE, /* change zone */ - add_or_change_zone_cb, - g_object_ref (dev)); - } - } -} - static void firewall_started (NMFirewallManager *manager, gpointer user_data) { NMPolicy *policy = (NMPolicy *) user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - NMConnection *connection; - NMSettingConnection *s_con; const GSList *iter; /* add interface of each device to correct zone */ - for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) { - NMDevice *dev = NM_DEVICE (iter->data); - - connection = nm_device_get_connection (dev); - if (!connection) - continue; - - s_con = nm_connection_get_setting_connection (connection); - if ( nm_device_get_state (dev) == NM_DEVICE_STATE_ACTIVATED - && !nm_device_uses_assumed_connection (dev)) { - nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (), - nm_device_get_ip_iface (dev), - nm_setting_connection_get_zone (s_con), - FALSE, /* still change zone */ - add_or_change_zone_cb, - g_object_ref (dev)); - } - } + for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) + nm_device_update_firewall_zone (iter->data); } static void @@ -1661,11 +1625,7 @@ connection_updated (NMSettings *settings, NMConnection *connection, gpointer user_data) { - NMPolicy *policy = (NMPolicy *) user_data; - - firewall_update_zone (policy, connection); - - schedule_activate_all (policy); + schedule_activate_all ((NMPolicy *) user_data); } static void @@ -1673,12 +1633,30 @@ connection_updated_by_user (NMSettings *settings, NMSettingsConnection *connection, gpointer user_data) { + NMPolicy *policy = (NMPolicy *) user_data; + NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); + const GSList *iter; + NMDevice *device = NULL; + + /* find device with given connection */ + for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) { + NMDevice *dev = NM_DEVICE (iter->data); + + if (nm_device_get_settings_connection (dev) == connection) { + device = dev; + break; + } + } + + if (device) + nm_device_reapply_settings_immediately (device); + /* Reset auto retries back to default since connection was updated */ nm_settings_connection_reset_autoconnect_retries (connection); } static void -_deactivate_if_active (NMManager *manager, NMConnection *connection) +_deactivate_if_active (NMManager *manager, NMSettingsConnection *connection) { const GSList *active, *iter; @@ -1688,14 +1666,14 @@ _deactivate_if_active (NMManager *manager, NMConnection *connection) NMActiveConnectionState state = nm_active_connection_get_state (ac); GError *error = NULL; - if (nm_active_connection_get_connection (ac) == connection && + if (nm_active_connection_get_settings_connection (ac) == connection && (state <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED)) { if (!nm_manager_deactivate_connection (manager, - nm_active_connection_get_path (ac), + nm_exported_object_get_path (NM_EXPORTED_OBJECT (ac)), NM_DEVICE_STATE_REASON_CONNECTION_REMOVED, &error)) { nm_log_warn (LOGD_DEVICE, "Connection '%s' disappeared, but error deactivating it: (%d) %s", - nm_connection_get_id (connection), + nm_settings_connection_get_id (connection), error ? error->code : -1, error ? error->message : "(unknown)"); g_clear_error (&error); @@ -1706,7 +1684,7 @@ _deactivate_if_active (NMManager *manager, NMConnection *connection) static void connection_removed (NMSettings *settings, - NMConnection *connection, + NMSettingsConnection *connection, gpointer user_data) { NMPolicy *policy = user_data; @@ -1726,7 +1704,7 @@ connection_visibility_changed (NMSettings *settings, if (nm_settings_connection_is_visible (connection)) schedule_activate_all (policy); else - _deactivate_if_active (priv->manager, NM_CONNECTION (connection)); + _deactivate_if_active (priv->manager, connection); } static void @@ -1748,20 +1726,20 @@ static void _connect_manager_signal (NMPolicy *policy, const char *name, gpointer callback) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - guint id; + gulong id; id = g_signal_connect (priv->manager, name, callback, policy); - priv->manager_ids = g_slist_prepend (priv->manager_ids, GUINT_TO_POINTER (id)); + priv->manager_ids = g_slist_prepend (priv->manager_ids, (gpointer) id); } static void _connect_settings_signal (NMPolicy *policy, const char *name, gpointer callback) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy); - guint id; + gulong id; id = g_signal_connect (priv->settings, name, callback, policy); - priv->settings_ids = g_slist_prepend (priv->settings_ids, GUINT_TO_POINTER (id)); + priv->settings_ids = g_slist_prepend (priv->settings_ids, (gpointer) id); } NMPolicy * @@ -1789,7 +1767,9 @@ nm_policy_new (NMManager *manager, NMSettings *settings) priv->orig_hostname = g_strdup (hostname); } - priv->fw_started_id = g_signal_connect (nm_firewall_manager_get (), "started", + priv->firewall_manager = g_object_ref (nm_firewall_manager_get ()); + + priv->fw_started_id = g_signal_connect (priv->firewall_manager, "started", G_CALLBACK (firewall_started), policy); priv->dns_manager = g_object_ref (nm_dns_manager_get ()); @@ -1799,12 +1779,12 @@ nm_policy_new (NMManager *manager, NMSettings *settings) priv->resolver = g_resolver_get_default (); - _connect_manager_signal (policy, "state-changed", global_state_changed); + _connect_manager_signal (policy, NM_MANAGER_STATE_CHANGED, global_state_changed); _connect_manager_signal (policy, "notify::" NM_MANAGER_HOSTNAME, hostname_changed); _connect_manager_signal (policy, "notify::" NM_MANAGER_SLEEPING, sleeping_changed); _connect_manager_signal (policy, "notify::" NM_MANAGER_NETWORKING_ENABLED, sleeping_changed); - _connect_manager_signal (policy, "device-added", device_added); - _connect_manager_signal (policy, "device-removed", device_removed); + _connect_manager_signal (policy, "internal-device-added", device_added); + _connect_manager_signal (policy, "internal-device-removed", device_removed); _connect_manager_signal (policy, NM_MANAGER_ACTIVE_CONNECTION_ADDED, active_connection_added); _connect_manager_signal (policy, NM_MANAGER_ACTIVE_CONNECTION_REMOVED, active_connection_removed); @@ -1896,9 +1876,11 @@ dispose (GObject *object) g_slist_free_full (priv->pending_secondaries, (GDestroyNotify) pending_secondary_data_free); priv->pending_secondaries = NULL; - if (priv->fw_started_id) { - g_signal_handler_disconnect (nm_firewall_manager_get (), priv->fw_started_id); + if (priv->firewall_manager) { + g_assert (priv->fw_started_id); + g_signal_handler_disconnect (priv->firewall_manager, priv->fw_started_id); priv->fw_started_id = 0; + g_clear_object (&priv->firewall_manager); } if (priv->dns_manager) { @@ -1907,11 +1889,11 @@ dispose (GObject *object) } for (iter = priv->manager_ids; iter; iter = g_slist_next (iter)) - g_signal_handler_disconnect (priv->manager, GPOINTER_TO_UINT (iter->data)); + g_signal_handler_disconnect (priv->manager, (gulong) iter->data); g_clear_pointer (&priv->manager_ids, g_slist_free); for (iter = priv->settings_ids; iter; iter = g_slist_next (iter)) - g_signal_handler_disconnect (priv->settings, GPOINTER_TO_UINT (iter->data)); + g_signal_handler_disconnect (priv->settings, (gulong) iter->data); g_clear_pointer (&priv->settings_ids, g_slist_free); for (iter = priv->dev_ids; iter; iter = g_slist_next (iter)) { @@ -1929,10 +1911,7 @@ dispose (GObject *object) connections = nm_manager_get_active_connections (priv->manager); g_assert (connections == NULL); - if (priv->reset_retries_id) { - g_source_remove (priv->reset_retries_id); - priv->reset_retries_id = 0; - } + nm_clear_g_source (&priv->reset_retries_id); g_clear_pointer (&priv->orig_hostname, g_free); g_clear_pointer (&priv->cur_hostname, g_free); diff --git a/src/nm-policy.h b/src/nm-policy.h index 76653529..7824f3ea 100644 --- a/src/nm-policy.h +++ b/src/nm-policy.h @@ -22,7 +22,7 @@ #ifndef __NETWORKMANAGER_POLICY_H__ #define __NETWORKMANAGER_POLICY_H__ -#include "nm-types.h" +#include "nm-default.h" #define NM_TYPE_POLICY (nm_policy_get_type ()) #define NM_POLICY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_POLICY, NMPolicy)) diff --git a/src/nm-ppp-manager-glue.h b/src/nm-ppp-manager-glue.h deleted file mode 100644 index 5aea527e..00000000 --- a/src/nm-ppp-manager-glue.h +++ /dev/null @@ -1,175 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_ppp_manager_MARSHAL_H__ -#define __dbus_glib_marshal_nm_ppp_manager_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -/* NONE:POINTER */ -#define dbus_glib_marshal_nm_ppp_manager_VOID__POINTER g_cclosure_marshal_VOID__POINTER -#define dbus_glib_marshal_nm_ppp_manager_NONE__POINTER dbus_glib_marshal_nm_ppp_manager_VOID__POINTER - -/* BOOLEAN:UINT,POINTER */ -extern void dbus_glib_marshal_nm_ppp_manager_BOOLEAN__UINT_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_ppp_manager_BOOLEAN__UINT_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef gboolean (*GMarshalFunc_BOOLEAN__UINT_POINTER) (gpointer data1, - guint arg_1, - gpointer arg_2, - gpointer data2); - GMarshalFunc_BOOLEAN__UINT_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - gboolean v_return; - - g_return_if_fail (return_value != NULL); - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_BOOLEAN__UINT_POINTER) (marshal_data ? marshal_data : cc->callback); - - v_return = callback (data1, - g_marshal_value_peek_uint (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - data2); - - g_value_set_boolean (return_value, v_return); -} - -/* BOOLEAN:BOXED,POINTER */ -extern void dbus_glib_marshal_nm_ppp_manager_BOOLEAN__BOXED_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_ppp_manager_BOOLEAN__BOXED_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef gboolean (*GMarshalFunc_BOOLEAN__BOXED_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer data2); - GMarshalFunc_BOOLEAN__BOXED_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - gboolean v_return; - - g_return_if_fail (return_value != NULL); - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_BOOLEAN__BOXED_POINTER) (marshal_data ? marshal_data : cc->callback); - - v_return = callback (data1, - g_marshal_value_peek_boxed (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - data2); - - g_value_set_boolean (return_value, v_return); -} - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_ppp_manager_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_ppp_manager_methods[] = { - { (GCallback) impl_ppp_manager_need_secrets, dbus_glib_marshal_nm_ppp_manager_NONE__POINTER, 0 }, - { (GCallback) impl_ppp_manager_set_ip4_config, dbus_glib_marshal_nm_ppp_manager_BOOLEAN__BOXED_POINTER, 84 }, - { (GCallback) impl_ppp_manager_set_ip6_config, dbus_glib_marshal_nm_ppp_manager_BOOLEAN__BOXED_POINTER, 150 }, - { (GCallback) impl_ppp_manager_set_state, dbus_glib_marshal_nm_ppp_manager_BOOLEAN__UINT_POINTER, 216 }, -}; - -const DBusGObjectInfo dbus_glib_nm_ppp_manager_object_info = { 1, - dbus_glib_nm_ppp_manager_methods, - 4, -"org.freedesktop.NetworkManager.PPP\0NeedSecrets\0A\0username\0O\0F\0N\0s\0password\0O\0F\0N\0s\0\0org.freedesktop.NetworkManager.PPP\0SetIp4Config\0S\0config\0I\0a{sv}\0\0org.freedesktop.NetworkManager.PPP\0SetIp6Config\0S\0config\0I\0a{sv}\0\0org.freedesktop.NetworkManager.PPP\0SetState\0S\0state\0I\0u\0\0\0", -"\0", -"\0" -}; - diff --git a/src/nm-properties-changed-signal.c b/src/nm-properties-changed-signal.c deleted file mode 100644 index c6dbb3d5..00000000 --- a/src/nm-properties-changed-signal.c +++ /dev/null @@ -1,248 +0,0 @@ -/* -*- 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) 2007 - 2008 Novell, Inc. - * Copyright (C) 2008 - 2012 Red Hat, Inc. - */ - -#include "config.h" - -#include -#include - -#include -#include "nm-logging.h" -#include "nm-properties-changed-signal.h" -#include "nm-dbus-glib-types.h" - -typedef struct { - GHashTable *exported_props; - guint signal_id; -} NMPropertiesChangedClassInfo; - -typedef struct { - GHashTable *hash; - guint signal_id; - guint idle_id; -} NMPropertiesChangedInfo; - -static GQuark -nm_properties_changed_signal_quark (void) -{ - static GQuark q; - - if (G_UNLIKELY (q == 0)) - q = g_quark_from_static_string ("nm-properties-changed-signal"); - - return q; -} - -static void -destroy_value (gpointer data) -{ - GValue *val = (GValue *) data; - - g_value_unset (val); - g_slice_free (GValue, val); -} - -static void -properties_changed_info_destroy (gpointer data) -{ - NMPropertiesChangedInfo *info = data; - - if (info->idle_id) - g_source_remove (info->idle_id); - - g_hash_table_destroy (info->hash); - g_slice_free (NMPropertiesChangedInfo, info); -} - -static void -add_to_string (gpointer key, gpointer value, gpointer user_data) -{ - const char *name = (const char *) key; - GString *buf = user_data; - GValue str_val = G_VALUE_INIT; - - g_value_init (&str_val, G_TYPE_STRING); - if (!g_value_transform ((GValue *) value, &str_val)) { - if (G_VALUE_HOLDS_OBJECT (value)) { - GObject *obj = g_value_get_object (value); - - if (obj) { - g_string_append_printf (buf, "{%s: %p (%s)}, ", name, obj, - G_OBJECT_TYPE_NAME (obj)); - } else - g_string_append_printf (buf, "{%s: %p}, ", name, obj); - } else - g_string_append_printf (buf, "{%s: }, ", name); - } else - g_string_append_printf (buf, "{%s: %s}, ", name, g_value_get_string (&str_val)); - g_value_unset (&str_val); -} - -static gboolean -properties_changed (gpointer data) -{ - GObject *object = G_OBJECT (data); - NMPropertiesChangedInfo *info = g_object_get_qdata (object, nm_properties_changed_signal_quark ()); - - g_assert (info); - - if (nm_logging_enabled (LOGL_DEBUG, LOGD_DBUS_PROPS)) { - GString *buf = g_string_new (NULL); - - g_hash_table_foreach (info->hash, add_to_string, buf); - nm_log_dbg (LOGD_DBUS_PROPS, "%s -> %s", G_OBJECT_TYPE_NAME (object), buf->str); - g_string_free (buf, TRUE); - } - - g_signal_emit (object, info->signal_id, 0, info->hash); - g_hash_table_remove_all (info->hash); - - return FALSE; -} - -static void -idle_id_reset (gpointer data) -{ - GObject *object = G_OBJECT (data); - NMPropertiesChangedInfo *info = g_object_get_qdata (object, nm_properties_changed_signal_quark ()); - - /* info is unset when the object is being destroyed */ - if (info) - info->idle_id = 0; -} - -static void -notify (GObject *object, GParamSpec *pspec) -{ - NMPropertiesChangedClassInfo *classinfo; - NMPropertiesChangedInfo *info; - const char *dbus_property_name = NULL; - GValue *value; - GType type; - - for (type = G_OBJECT_TYPE (object); type; type = g_type_parent (type)) { - classinfo = g_type_get_qdata (type, nm_properties_changed_signal_quark ()); - if (!classinfo) - continue; - - dbus_property_name = g_hash_table_lookup (classinfo->exported_props, pspec->name); - if (dbus_property_name) - break; - } - if (!dbus_property_name) { - nm_log_trace (LOGD_DBUS_PROPS, "ignoring notification for prop %s on type %s", - pspec->name, G_OBJECT_TYPE_NAME (object)); - return; - } - - info = g_object_get_qdata (object, nm_properties_changed_signal_quark ()); - if (!info) { - info = g_slice_new0 (NMPropertiesChangedInfo); - info->hash = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, destroy_value); - info->signal_id = classinfo->signal_id; - - g_object_set_qdata_full (object, nm_properties_changed_signal_quark (), - info, properties_changed_info_destroy); - } - - value = g_slice_new0 (GValue); - g_value_init (value, pspec->value_type); - g_object_get_property (object, pspec->name, value); - g_hash_table_insert (info->hash, (char *) dbus_property_name, value); - - if (!info->idle_id) - info->idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, properties_changed, object, idle_id_reset); -} - -static NMPropertiesChangedClassInfo * -nm_properties_changed_signal_setup_type (GType type) -{ - NMPropertiesChangedClassInfo *classinfo; - NMPropertiesChangedClassInfo *parent_classinfo = NULL; - GObjectClass *object_class; - GType parent; - - classinfo = g_slice_new (NMPropertiesChangedClassInfo); - g_type_set_qdata (type, nm_properties_changed_signal_quark (), classinfo); - - object_class = g_type_class_ref (type); - object_class->notify = notify; - g_type_class_unref (object_class); - - classinfo->exported_props = g_hash_table_new (g_str_hash, g_str_equal); - - /* See if we've already added the signal to a parent class. (We can't just use - * g_signal_lookup() here because it prints a warning if the signal doesn't exist!) - */ - parent = g_type_parent (type); - while (parent) { - parent_classinfo = g_type_get_qdata (parent, nm_properties_changed_signal_quark ()); - if (parent_classinfo) - break; - parent = g_type_parent (parent); - } - - if (parent_classinfo) - classinfo->signal_id = parent_classinfo->signal_id; - else { - classinfo->signal_id = g_signal_new ("properties-changed", - type, - G_SIGNAL_RUN_FIRST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, 1, DBUS_TYPE_G_MAP_OF_VARIANT); - } - - return classinfo; -} - -void -nm_properties_changed_signal_add_property (GType type, - const char *dbus_property_name, - const char *gobject_property_name) -{ - NMPropertiesChangedClassInfo *classinfo; - char *hyphen_name, *p; - - classinfo = g_type_get_qdata (type, nm_properties_changed_signal_quark ()); - if (!classinfo) - classinfo = nm_properties_changed_signal_setup_type (type); - - g_assert (!g_hash_table_contains (classinfo->exported_props, (char *) gobject_property_name)); - g_hash_table_insert (classinfo->exported_props, - (char *) gobject_property_name, - (char *) dbus_property_name); - - if (!strchr (gobject_property_name, '_')) - return; - hyphen_name = g_strdup (gobject_property_name); - for (p = hyphen_name; *p; p++) { - if (*p == '_') - *p = '-'; - } - g_assert (!g_hash_table_contains (classinfo->exported_props, hyphen_name)); - g_hash_table_insert (classinfo->exported_props, - (char *) g_intern_string (hyphen_name), - (char *) dbus_property_name); - g_free (hyphen_name); -} diff --git a/src/nm-properties-changed-signal.h b/src/nm-properties-changed-signal.h deleted file mode 100644 index 97a3b2c0..00000000 --- a/src/nm-properties-changed-signal.h +++ /dev/null @@ -1,31 +0,0 @@ -/* -*- 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) 2007 - 2008 Novell, Inc. - * Copyright (C) 2008 Red Hat, Inc. - */ - -#ifndef _NM_PROPERTIES_CHANGED_SIGNAL_H_ -#define _NM_PROPERTIES_CHANGED_SIGNAL_H_ - -#include - -void nm_properties_changed_signal_add_property (GType type, - const char *dbus_property_name, - const char *gobject_property_name); - -#endif /* _NM_PROPERTIES_CHANGED_SIGNAL_H_ */ diff --git a/src/nm-rfkill-manager.c b/src/nm-rfkill-manager.c index 27f3ca01..76703b20 100644 --- a/src/nm-rfkill-manager.c +++ b/src/nm-rfkill-manager.c @@ -24,7 +24,7 @@ #include #include "nm-rfkill-manager.h" -#include "nm-logging.h" +#include "nm-default.h" typedef struct { GUdevClient *client; @@ -268,8 +268,6 @@ rfkill_type_to_enum (const char *str) return RFKILL_TYPE_WLAN; else if (!strcmp (str, "wwan")) return RFKILL_TYPE_WWAN; - else if (!strcmp (str, "wimax")) - return RFKILL_TYPE_WIMAX; return RFKILL_TYPE_UNKNOWN; } diff --git a/src/nm-rfkill-manager.h b/src/nm-rfkill-manager.h index 220f3c2c..0084364c 100644 --- a/src/nm-rfkill-manager.h +++ b/src/nm-rfkill-manager.h @@ -19,29 +19,27 @@ * Copyright (C) 2007 - 2013 Red Hat, Inc. */ -#include -#include "nm-types.h" +#include "nm-default.h" #ifndef __NETWORKMANAGER_RFKILL_MANAGER_H__ #define __NETWORKMANAGER_RFKILL_MANAGER_H__ -typedef enum { +typedef enum { /*< skip >*/ RFKILL_UNBLOCKED = 0, RFKILL_SOFT_BLOCKED = 1, RFKILL_HARD_BLOCKED = 2 } RfKillState; -typedef enum { +typedef enum { /*< skip >*/ RFKILL_TYPE_WLAN = 0, RFKILL_TYPE_WWAN = 1, - RFKILL_TYPE_WIMAX = 2, /* UNKNOWN and MAX should always be 1 more than * the last rfkill type since RFKILL_TYPE_MAX is * used as an array size. */ - RFKILL_TYPE_UNKNOWN = 3, /* KEEP LAST */ + RFKILL_TYPE_UNKNOWN, /* KEEP LAST */ RFKILL_TYPE_MAX = RFKILL_TYPE_UNKNOWN } RfKillType; diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index bb21384e..5af0b917 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -26,8 +26,7 @@ #include "nm-platform.h" #include "nmp-object.h" #include "nm-core-internal.h" -#include "nm-logging.h" -#include "gsystem-local-alloc.h" +#include "nm-default.h" #include "NetworkManagerUtils.h" /* if within half a second after adding an IP address a matching device-route shows @@ -148,7 +147,7 @@ static gboolean _ip4_device_routes_cancel (NMRouteManager *self); /*********************************************************************************************/ -#if defined (NM_MORE_ASSERTS) && !defined (G_DISABLE_ASSERT) +#if NM_MORE_ASSERTS && !defined (G_DISABLE_ASSERT) inline static void ASSERT_route_index_valid (const VTableIP *vtable, const GArray *entries, const RouteIndex *index, gboolean unique_ifindexes) { @@ -468,12 +467,12 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const if (_LOGt_ENABLED (vtable->vt->addr_family)) { for (i = 0; i < known_routes_idx->len; i++) { _LOGt (vtable->vt->addr_family, "%3d: sync new route #%u: %s", - ifindex, i, vtable->vt->route_to_string (VTABLE_ROUTE_INDEX (vtable, known_routes, i))); + ifindex, i, vtable->vt->route_to_string (VTABLE_ROUTE_INDEX (vtable, known_routes, i), NULL, 0)); } for (i = 0; i < ipx_routes->index->len; i++) _LOGt (vtable->vt->addr_family, "%3d: STATE: has #%u - %s (%lld)", ifindex, i, - vtable->vt->route_to_string (ipx_routes->index->entries[i]), + vtable->vt->route_to_string (ipx_routes->index->entries[i], NULL, 0), (long long) g_array_index (ipx_routes->effective_metrics, gint64, i)); } @@ -513,7 +512,8 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const cur_ipx_route->rx.ifindex = ifindex; cur_ipx_route->rx.metric = vtable->vt->metric_normalize (cur_ipx_route->rx.metric); ipx_routes_changed = TRUE; - _LOGt (vtable->vt->addr_family, "%3d: STATE: update #%u - %s", ifindex, i_ipx_routes, vtable->vt->route_to_string (cur_ipx_route)); + _LOGt (vtable->vt->addr_family, "%3d: STATE: update #%u - %s", ifindex, i_ipx_routes, + vtable->vt->route_to_string (cur_ipx_route, NULL, 0)); } } else if (cur_known_route) { g_assert (!cur_ipx_route || route_id_cmp_result > 0); @@ -571,7 +571,8 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const && cur_plat_route->rx.metric == *p_effective_metric) { /* we are about to delete cur_ipx_route and we have a matching route * in platform. Delete it. */ - _LOGt (vtable->vt->addr_family, "%3d: platform rt-rm #%u - %s", ifindex, i_plat_routes, vtable->vt->route_to_string (cur_plat_route)); + _LOGt (vtable->vt->addr_family, "%3d: platform rt-rm #%u - %s", ifindex, i_plat_routes, + vtable->vt->route_to_string (cur_plat_route, NULL, 0)); vtable->vt->route_delete (priv->platform, ifindex, cur_plat_route); } } @@ -583,7 +584,8 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const for (i = 0; i < to_delete_indexes->len; i++) { guint idx = g_array_index (to_delete_indexes, guint, i); - _LOGt (vtable->vt->addr_family, "%3d: STATE: delete #%u - %s", ifindex, idx, vtable->vt->route_to_string (ipx_routes->index->entries[idx])); + _LOGt (vtable->vt->addr_family, "%3d: STATE: delete #%u - %s", ifindex, idx, + vtable->vt->route_to_string (ipx_routes->index->entries[idx], NULL, 0)); g_array_index (to_delete_indexes, guint, i) = _route_index_reverse_idx (vtable, ipx_routes->index, idx, ipx_routes->entries); } g_array_sort (to_delete_indexes, (GCompareFunc) _sort_indexes_cmp); @@ -607,7 +609,8 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const g_array_index (ipx_routes->effective_metrics_reverse, gint64, j++) = -1; - _LOGt (vtable->vt->addr_family, "%3d: STATE: added #%u - %s", ifindex, ipx_routes->entries->len - 1, vtable->vt->route_to_string (ipx_route)); + _LOGt (vtable->vt->addr_family, "%3d: STATE: added #%u - %s", ifindex, ipx_routes->entries->len - 1, + vtable->vt->route_to_string (ipx_route, NULL, 0)); } g_ptr_array_unref (to_add_routes); } @@ -694,7 +697,7 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const next: _LOGt (vtable->vt->addr_family, "%3d: new metric #%u - %s (%lld)", ifindex, i_ipx_routes, - vtable->vt->route_to_string (cur_ipx_route), + vtable->vt->route_to_string (cur_ipx_route, NULL, 0), (long long) *p_effective_metric); } } @@ -717,7 +720,7 @@ next: g_assert (cur_plat_route->rx.ifindex == ifindex); - _LOGt (vtable->vt->addr_family, "%3d: platform rt #%u - %s", ifindex, i_plat_routes, vtable->vt->route_to_string (cur_plat_route)); + _LOGt (vtable->vt->addr_family, "%3d: platform rt #%u - %s", ifindex, i_plat_routes, vtable->vt->route_to_string (cur_plat_route, NULL, 0)); /* skip over @cur_ipx_route that are ordered before @cur_plat_route */ while ( cur_ipx_route @@ -871,7 +874,7 @@ next: _LOGD (vtable->vt->addr_family, "ignore error adding IPv%c route to kernel: %s", vtable->vt->is_ip4 ? '4' : '6', - vtable->vt->route_to_string (cur_ipx_route)); + vtable->vt->route_to_string (cur_ipx_route, NULL, 0)); } else { /* Remember that there was a failure, but for now continue trying * to sync the remaining routes. */ @@ -938,8 +941,11 @@ nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray gboolean nm_route_manager_route_flush (NMRouteManager *self, int ifindex) { - return nm_route_manager_ip4_route_sync (self, ifindex, NULL, FALSE, TRUE) - && nm_route_manager_ip6_route_sync (self, ifindex, NULL, FALSE, TRUE); + bool success = TRUE; + + success &= (bool) nm_route_manager_ip4_route_sync (self, ifindex, NULL, FALSE, TRUE); + success &= (bool) nm_route_manager_ip6_route_sync (self, ifindex, NULL, FALSE, TRUE); + return success; } /*********************************************************************************************/ @@ -1006,7 +1012,6 @@ _ip4_device_routes_ip4_route_changed (NMPlatform *platform, int ifindex, const NMPlatformIP4Route *route, NMPlatformSignalChangeType change_type, - NMPlatformReason reason, NMRouteManager *self) { NMRouteManagerPrivate *priv; diff --git a/src/nm-route-manager.h b/src/nm-route-manager.h index 1e4ce484..9a08496f 100644 --- a/src/nm-route-manager.h +++ b/src/nm-route-manager.h @@ -18,9 +18,8 @@ * Copyright (C) 2015 Red Hat, Inc. */ -#include -#include "nm-types.h" +#include "nm-default.h" #ifndef __NETWORKMANAGER_ROUTE_MANAGER_H__ #define __NETWORKMANAGER_ROUTE_MANAGER_H__ diff --git a/src/nm-session-monitor-ck.c b/src/nm-session-monitor-ck.c deleted file mode 100644 index 964874bf..00000000 --- a/src/nm-session-monitor-ck.c +++ /dev/null @@ -1,503 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* 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. - * - * (C) Copyright 2008 - 2010 Red Hat, Inc. - * Author: David Zeuthen - * Author: Dan Williams - */ - -#include "config.h" - -#include -#include -#include -#include -#include "nm-logging.h" - -#include "nm-session-utils.h" -#include "nm-session-monitor.h" -#include "nm-errors.h" - -/* - * SECTION:nm-session-monitor - * @title: NMSessionMonitor - * @short_description: Monitor sessions - * - * The #NMSessionMonitor class is a utility class to track and monitor sessions. - */ - -struct _NMSessionMonitor { - GObject parent_instance; - - GKeyFile *database; - GFileMonitor *database_monitor; - time_t database_mtime; - GHashTable *sessions_by_uid; - GHashTable *sessions_by_user; -}; - -struct _NMSessionMonitorClass { - GObjectClass parent_class; - - void (*changed) (NMSessionMonitor *monitor); -}; - - -enum { - CHANGED, - LAST_SIGNAL, -}; -static guint signals[LAST_SIGNAL] = {0}; - -G_DEFINE_TYPE (NMSessionMonitor, nm_session_monitor, G_TYPE_OBJECT); - -/********************************************************************/ - -typedef struct { - char *user; - uid_t uid; - gboolean local; - gboolean active; -} Session; - -static void -session_free (Session *s) -{ - g_free (s->user); - memset (s, 0, sizeof (Session)); - g_free (s); -} - -static gboolean -check_key (GKeyFile *keyfile, const char *group, const char *key, GError **error) -{ - if (g_key_file_has_key (keyfile, group, key, error)) - return TRUE; - - if (!error) { - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "ConsoleKit database " CKDB_PATH " group '%s' had no '%s' key", - group, key); - } - return FALSE; -} - -static Session * -session_new (GKeyFile *keyfile, const char *group, GError **error) -{ - GError *local = NULL; - Session *s; - const char *uname = NULL; - - s = g_new0 (Session, 1); - g_assert (s); - - s->uid = G_MAXUINT; /* paranoia */ - if (!check_key (keyfile, group, "uid", &local)) - goto error; - s->uid = (uid_t) g_key_file_get_integer (keyfile, group, "uid", &local); - if (local) - goto error; - - if (!check_key (keyfile, group, "is_active", &local)) - goto error; - s->active = g_key_file_get_boolean (keyfile, group, "is_active", &local); - if (local) - goto error; - - if (!check_key (keyfile, group, "is_local", &local)) - goto error; - s->local = g_key_file_get_boolean (keyfile, group, "is_local", &local); - if (local) - goto error; - - if (!nm_session_uid_to_user (s->uid, &uname, error)) - return FALSE; - s->user = g_strdup (uname); - - return s; - -error: - session_free (s); - g_propagate_error (error, local); - return NULL; -} - -static void -session_merge (Session *src, Session *dest) -{ - g_return_if_fail (src != NULL); - g_return_if_fail (dest != NULL); - - g_warn_if_fail (g_strcmp0 (src->user, dest->user) == 0); - g_warn_if_fail (src->uid == dest->uid); - - dest->local = (dest->local || src->local); - dest->active = (dest->active || src->active); -} - -/********************************************************************/ - -static void -free_database (NMSessionMonitor *self) -{ - if (self->database != NULL) { - g_key_file_free (self->database); - self->database = NULL; - } - - g_hash_table_remove_all (self->sessions_by_uid); - g_hash_table_remove_all (self->sessions_by_user); -} - -static gboolean -reload_database (NMSessionMonitor *self, GError **error) -{ - struct stat statbuf; - char **groups = NULL; - gsize len = 0, i; - Session *s; - - free_database (self); - - errno = 0; - if (stat (CKDB_PATH, &statbuf) != 0) { - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Error statting file " CKDB_PATH ": %s", - strerror (errno)); - goto error; - } - self->database_mtime = statbuf.st_mtime; - - self->database = g_key_file_new (); - if (!g_key_file_load_from_file (self->database, CKDB_PATH, G_KEY_FILE_NONE, error)) - goto error; - - groups = g_key_file_get_groups (self->database, &len); - if (!groups) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Could not load groups from " CKDB_PATH ""); - goto error; - } - - for (i = 0; i < len; i++) { - Session *found; - - if (!g_str_has_prefix (groups[i], "Session ")) - continue; - - s = session_new (self->database, groups[i], error); - if (!s) - goto error; - - found = g_hash_table_lookup (self->sessions_by_user, (gpointer) s->user); - if (found) { - session_merge (s, found); - session_free (s); - } else { - /* Entirely new user */ - g_hash_table_insert (self->sessions_by_user, (gpointer) s->user, s); - g_hash_table_insert (self->sessions_by_uid, GUINT_TO_POINTER (s->uid), s); - } - } - - g_strfreev (groups); - return TRUE; - -error: - if (groups) - g_strfreev (groups); - free_database (self); - return FALSE; -} - -static gboolean -ensure_database (NMSessionMonitor *self, GError **error) -{ - gboolean ret = FALSE; - - if (self->database != NULL) { - struct stat statbuf; - - errno = 0; - if (stat (CKDB_PATH, &statbuf) != 0) { - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Error statting file " CKDB_PATH " to check timestamp: %s", - strerror (errno)); - goto out; - } - - if (statbuf.st_mtime == self->database_mtime) { - ret = TRUE; - goto out; - } - } - - ret = reload_database (self, error); - -out: - return ret; -} - -static void -on_file_monitor_changed (GFileMonitor * file_monitor, - GFile * file, - GFile * other_file, - GFileMonitorEvent event_type, - gpointer user_data) -{ - NMSessionMonitor *self = NM_SESSION_MONITOR (user_data); - - /* throw away cache */ - free_database (self); - - g_signal_emit (self, signals[CHANGED], 0); -} - -static void -nm_session_monitor_init (NMSessionMonitor *self) -{ - GError *error = NULL; - GFile *file; - - /* Sessions-by-user is responsible for destroying the Session objects */ - self->sessions_by_user = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, (GDestroyNotify) session_free); - self->sessions_by_uid = g_hash_table_new (g_direct_hash, g_direct_equal); - - - if (!ensure_database (self, &error)) { - nm_log_dbg (LOGD_CORE, "Error loading " CKDB_PATH ": %s", error->message); - - /* Ignore the first error, the CK database might not exist yet */ - g_error_free (error); - error = NULL; - } - - file = g_file_new_for_path (CKDB_PATH); - self->database_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &error); - g_object_unref (file); - if (self->database_monitor == NULL) { - nm_log_err (LOGD_CORE, "Error monitoring " CKDB_PATH ": %s", error->message); - g_error_free (error); - } else { - g_signal_connect (self->database_monitor, - "changed", - G_CALLBACK (on_file_monitor_changed), - self); - } -} - -static void -finalize (GObject *object) -{ - NMSessionMonitor *self = NM_SESSION_MONITOR (object); - - if (self->database_monitor != NULL) - g_object_unref (self->database_monitor); - - free_database (self); - - if (G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize != NULL) - G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize (object); -} - -static void -nm_session_monitor_class_init (NMSessionMonitorClass *klass) -{ - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->finalize = finalize; - - /** - * NMSessionMonitor::changed: - * @monitor: A #NMSessionMonitor - * - * Emitted when something changes. - */ - signals[CHANGED] = g_signal_new (NM_SESSION_MONITOR_CHANGED, - NM_TYPE_SESSION_MONITOR, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMSessionMonitorClass, changed), - NULL, /* accumulator */ - NULL, /* accumulator data */ - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -NMSessionMonitor * -nm_session_monitor_get (void) -{ - static NMSessionMonitor *singleton = NULL; - - if (!singleton) - singleton = NM_SESSION_MONITOR (g_object_new (NM_TYPE_SESSION_MONITOR, NULL)); - return singleton; -} - -/* ---------------------------------------------------------------------------------------------------- */ - -/** - * nm_session_monitor_user_has_session: - * @monitor: A #NMSessionMonitor. - * @username: A username. - * @error: Return location for error. - * - * Checks whether the given @username is logged into a session or not. - * - * Returns: %FALSE if @error is set otherwise %TRUE if the given @username is - * currently logged into a session. - */ -gboolean -nm_session_monitor_user_has_session (NMSessionMonitor *monitor, - const char *username, - uid_t *out_uid, - GError **error) -{ - Session *s; - - if (!ensure_database (monitor, error)) - return FALSE; - - s = g_hash_table_lookup (monitor->sessions_by_user, (gpointer) username); - if (!s) { - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "No session found for user '%s'", - username); - return FALSE; - } - - if (out_uid) - *out_uid = s->uid; - return TRUE; -} - -/** - * nm_session_monitor_uid_has_session: - * @monitor: A #NMSessionMonitor. - * @uid: A user ID. - * @error: Return location for error. - * - * Checks whether the given @uid is logged into a session or not. - * - * Returns: %FALSE if @error is set otherwise %TRUE if the given @uid is - * currently logged into a session. - */ -gboolean -nm_session_monitor_uid_has_session (NMSessionMonitor *monitor, - uid_t uid, - const char **out_user, - GError **error) -{ - Session *s; - - if (!ensure_database (monitor, error)) - return FALSE; - - s = g_hash_table_lookup (monitor->sessions_by_uid, GUINT_TO_POINTER (uid)); - if (!s) { - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "No session found for uid %d", - uid); - return FALSE; - } - - if (out_user) - *out_user = s->user; - return TRUE; -} - -/** - * nm_session_monitor_user_active: - * @monitor: A #NMSessionMonitor. - * @username: A username. - * @error: Return location for error. - * - * Checks whether the given @username is logged into a active session or not. - * - * Returns: %FALSE if @error is set otherwise %TRUE if the given @username is - * logged into an active session. - */ -gboolean -nm_session_monitor_user_active (NMSessionMonitor *monitor, - const char *username, - GError **error) -{ - Session *s; - - if (!ensure_database (monitor, error)) - return FALSE; - - s = g_hash_table_lookup (monitor->sessions_by_user, (gpointer) username); - if (!s) { - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "No session found for user '%s'", - username); - return FALSE; - } - - return s->active; -} - -/** - * nm_session_monitor_uid_active: - * @monitor: A #NMSessionMonitor. - * @uid: A user ID. - * @error: Return location for error. - * - * Checks whether the given @uid is logged into a active session or not. - * - * Returns: %FALSE if @error is set otherwise %TRUE if the given @uid is - * logged into an active session. - */ -gboolean -nm_session_monitor_uid_active (NMSessionMonitor *monitor, - uid_t uid, - GError **error) -{ - Session *s; - - if (!ensure_database (monitor, error)) - return FALSE; - - s = g_hash_table_lookup (monitor->sessions_by_uid, GUINT_TO_POINTER (uid)); - if (!s) { - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "No session found for uid '%d'", - uid); - return FALSE; - } - - return s->active; -} - diff --git a/src/nm-session-monitor-null.c b/src/nm-session-monitor-null.c deleted file mode 100644 index bffb75d3..00000000 --- a/src/nm-session-monitor-null.c +++ /dev/null @@ -1,169 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* 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. - * - * (C) Copyright 2008 - 2010 Red Hat, Inc. - * Author: David Zeuthen - * Author: Dan Williams - */ - -#include "config.h" - -#include -#include "nm-logging.h" - -#include "nm-session-utils.h" -#include "nm-session-monitor.h" - -/* - * SECTION:nm-session-monitor - * @title: NMSessionMonitor - * @short_description: Monitor sessions - * - * The #NMSessionMonitor class is a utility class to track and monitor sessions. - */ - -struct _NMSessionMonitor { - GObject parent_instance; -}; - -struct _NMSessionMonitorClass { - GObjectClass parent_class; - - void (*changed) (NMSessionMonitor *monitor); -}; - - -enum { - CHANGED, - LAST_SIGNAL, -}; -static guint signals[LAST_SIGNAL] = {0}; - -G_DEFINE_TYPE (NMSessionMonitor, nm_session_monitor, G_TYPE_OBJECT); - -/********************************************************************/ - -static void -nm_session_monitor_init (NMSessionMonitor *self) -{ -} - -static void -nm_session_monitor_class_init (NMSessionMonitorClass *klass) -{ - /** - * NMSessionMonitor::changed: - * @monitor: A #NMSessionMonitor - * - * Emitted when something changes. - */ - signals[CHANGED] = g_signal_new (NM_SESSION_MONITOR_CHANGED, - NM_TYPE_SESSION_MONITOR, - G_SIGNAL_RUN_LAST, - 0, NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -NMSessionMonitor * -nm_session_monitor_get (void) -{ - static NMSessionMonitor *singleton = NULL; - - if (!singleton) - singleton = g_object_new (NM_TYPE_SESSION_MONITOR, NULL); - return singleton; -} - -/* ---------------------------------------------------------------------------------------------------- */ - -/** - * nm_session_monitor_user_has_session: - * @monitor: A #NMSessionMonitor. - * @username: A username. - * @error: Return location for error. - * - * Checks whether the given @username is logged into a session or not. - * - * Returns: %FALSE if @error is set otherwise %TRUE if the given @username is - * currently logged into a session. - */ -gboolean -nm_session_monitor_user_has_session (NMSessionMonitor *monitor, - const char *username, - uid_t *out_uid, - GError **error) -{ - return nm_session_user_to_uid (username, out_uid, error); -} - -/** - * nm_session_monitor_uid_has_session: - * @monitor: A #NMSessionMonitor. - * @uid: A user ID. - * @error: Return location for error. - * - * Checks whether the given @uid is logged into a session or not. - * - * Returns: %FALSE if @error is set otherwise %TRUE if the given @uid is - * currently logged into a session. - */ -gboolean -nm_session_monitor_uid_has_session (NMSessionMonitor *monitor, - uid_t uid, - const char **out_user, - GError **error) -{ - return nm_session_uid_to_user (uid, out_user, error); -} - -/** - * nm_session_monitor_user_active: - * @monitor: A #NMSessionMonitor. - * @username: A username. - * @error: Return location for error. - * - * Checks whether the given @username is logged into a active session or not. - * - * Returns: %FALSE if @error is set otherwise %TRUE if the given @username is - * logged into an active session. - */ -gboolean -nm_session_monitor_user_active (NMSessionMonitor *monitor, - const char *username, - GError **error) -{ - return TRUE; -} - -/** - * nm_session_monitor_uid_active: - * @monitor: A #NMSessionMonitor. - * @uid: A user ID. - * @error: Return location for error. - * - * Checks whether the given @uid is logged into a active session or not. - * - * Returns: %FALSE if @error is set otherwise %TRUE if the given @uid is - * logged into an active session. - */ -gboolean -nm_session_monitor_uid_active (NMSessionMonitor *monitor, - uid_t uid, - GError **error) -{ - return TRUE; -} - diff --git a/src/nm-session-monitor-systemd.c b/src/nm-session-monitor-systemd.c deleted file mode 100644 index dcb0004d..00000000 --- a/src/nm-session-monitor-systemd.c +++ /dev/null @@ -1,268 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* - * Copyright (C) 2011 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - * Author: Matthias Clasen - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "nm-session-utils.h" -#include "nm-session-monitor.h" -#include "nm-logging.h" - -/********************************************************************/ - -typedef struct { - GSource source; - GPollFD pollfd; - sd_login_monitor *monitor; -} SdSource; - -static gboolean -sd_source_prepare (GSource *source, gint *timeout) -{ - *timeout = -1; - return FALSE; -} - -static gboolean -sd_source_check (GSource *source) -{ - SdSource *sd_source = (SdSource *) source; - - return sd_source->pollfd.revents != 0; -} - -static gboolean -sd_source_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data) - -{ - SdSource *sd_source = (SdSource *)source; - gboolean ret; - - g_warn_if_fail (callback != NULL); - ret = (*callback) (user_data); - sd_login_monitor_flush (sd_source->monitor); - return ret; -} - -static void -sd_source_finalize (GSource *source) -{ - SdSource *sd_source = (SdSource*) source; - - sd_login_monitor_unref (sd_source->monitor); -} - -static GSourceFuncs sd_source_funcs = { - sd_source_prepare, - sd_source_check, - sd_source_dispatch, - sd_source_finalize -}; - -static GSource * -sd_source_new (void) -{ - GSource *source; - SdSource *sd_source; - int ret; - - source = g_source_new (&sd_source_funcs, sizeof (SdSource)); - sd_source = (SdSource *)source; - - ret = sd_login_monitor_new (NULL, &sd_source->monitor); - if (ret < 0) - g_printerr ("Error getting login monitor: %d", ret); - else { - sd_source->pollfd.fd = sd_login_monitor_get_fd (sd_source->monitor); - sd_source->pollfd.events = G_IO_IN; - g_source_add_poll (source, &sd_source->pollfd); - } - - return source; -} - -struct _NMSessionMonitor { - GObject parent_instance; - - GSource *sd_source; -}; - -struct _NMSessionMonitorClass { - GObjectClass parent_class; - - void (*changed) (NMSessionMonitor *monitor); -}; - - -enum { - CHANGED_SIGNAL, - LAST_SIGNAL, -}; -static guint signals[LAST_SIGNAL] = {0}; - -G_DEFINE_TYPE (NMSessionMonitor, nm_session_monitor, G_TYPE_OBJECT); - -/* ---------------------------------------------------------------------------------------------------- */ - -static gboolean -sessions_changed (gpointer user_data) -{ - NMSessionMonitor *monitor = NM_SESSION_MONITOR (user_data); - - g_signal_emit (monitor, signals[CHANGED_SIGNAL], 0); - return TRUE; -} - - -static void -nm_session_monitor_init (NMSessionMonitor *monitor) -{ - monitor->sd_source = sd_source_new (); - g_source_set_callback (monitor->sd_source, sessions_changed, monitor, NULL); - g_source_attach (monitor->sd_source, NULL); -} - -static void -nm_session_monitor_finalize (GObject *object) -{ - NMSessionMonitor *monitor = NM_SESSION_MONITOR (object); - - if (monitor->sd_source != NULL) { - g_source_destroy (monitor->sd_source); - g_source_unref (monitor->sd_source); - } - - if (G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize != NULL) - G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize (object); -} - -static void -nm_session_monitor_class_init (NMSessionMonitorClass *klass) -{ - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (klass); - gobject_class->finalize = nm_session_monitor_finalize; - - /** - * NMSessionMonitor::changed: - * @monitor: A #NMSessionMonitor - * - * Emitted when something changes. - */ - signals[CHANGED_SIGNAL] = g_signal_new ("changed", - NM_TYPE_SESSION_MONITOR, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMSessionMonitorClass, changed), - NULL, /* accumulator */ - NULL, /* accumulator data */ - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); -} - -NMSessionMonitor * -nm_session_monitor_get (void) -{ - static NMSessionMonitor *singleton = NULL; - - if (!singleton) - singleton = g_object_new (NM_TYPE_SESSION_MONITOR, NULL); - return singleton; -} - -gboolean -nm_session_monitor_user_has_session (NMSessionMonitor *monitor, - const char *username, - uid_t *out_uid, - GError **error) -{ - uid_t uid; - - if (!nm_session_user_to_uid (username, &uid, error)) - return FALSE; - - if (out_uid) - *out_uid = uid; - - return nm_session_monitor_uid_has_session (monitor, uid, NULL, error); -} - -gboolean -nm_session_monitor_user_active (NMSessionMonitor *monitor, - const char *username, - GError **error) -{ - uid_t uid; - - if (!nm_session_user_to_uid (username, &uid, error)) - return FALSE; - - return nm_session_monitor_uid_active (monitor, uid, error); -} - -gboolean -nm_session_monitor_uid_has_session (NMSessionMonitor *monitor, - uid_t uid, - const char **out_user, - GError **error) -{ - int num_sessions; - - if (!nm_session_uid_to_user (uid, out_user, error)) - return FALSE; - - /* Get all sessions (including inactive ones) for the user */ - num_sessions = sd_uid_get_sessions (uid, 0, NULL); - if (num_sessions < 0) { - nm_log_warn (LOGD_CORE, "Failed to get systemd sessions for uid %d: %d", - uid, num_sessions); - return FALSE; - } - return num_sessions > 0; -} - -gboolean -nm_session_monitor_uid_active (NMSessionMonitor *monitor, - uid_t uid, - GError **error) -{ - int num_sessions; - - /* Get active sessions for the user */ - num_sessions = sd_uid_get_sessions (uid, 1, NULL); - if (num_sessions < 0) { - nm_log_warn (LOGD_CORE, "Failed to get active systemd sessions for uid %d: %d", - uid, num_sessions); - return FALSE; - } - return num_sessions > 0; -} diff --git a/src/nm-session-monitor.c b/src/nm-session-monitor.c new file mode 100644 index 00000000..461195b0 --- /dev/null +++ b/src/nm-session-monitor.c @@ -0,0 +1,450 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* 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. + * + * (C) Copyright 2008 - 2015 Red Hat, Inc. + * Author: David Zeuthen + * Author: Dan Williams + * Author: Matthias Clasen + * Author: Pavel Šimerda + */ +#include "config.h" + +#include +#include +#include +#include + +#include "nm-default.h" +#include "nm-session-monitor.h" +#include "NetworkManagerUtils.h" + +#ifdef SESSION_TRACKING_SYSTEMD +#include +#endif + +/********************************************************************/ + +/* + * SECTION:nm-session-monitor + * @title: NMSessionMonitor + * @short_description: Monitor sessions + * + * The #NMSessionMonitor class is a utility class to track and monitor sessions. + */ +struct _NMSessionMonitor { + GObject parent_instance; + +#ifdef SESSION_TRACKING_SYSTEMD + struct { + sd_login_monitor *monitor; + guint watch; + } sd; +#endif + +#ifdef SESSION_TRACKING_CONSOLEKIT + struct { + GFileMonitor *monitor; + GHashTable *cache; + time_t timestamp; + } ck; +#endif +}; + +struct _NMSessionMonitorClass { + GObjectClass parent_class; + + void (*changed) (NMSessionMonitor *monitor); +}; + +G_DEFINE_TYPE (NMSessionMonitor, nm_session_monitor, G_TYPE_OBJECT); + +enum { + CHANGED, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +/********************************************************************/ + +#ifdef SESSION_TRACKING_SYSTEMD +static gboolean +sd_session_exists (NMSessionMonitor *monitor, uid_t uid, gboolean active) +{ + int status; + + if (!monitor->sd.monitor) + return FALSE; + + status = sd_uid_get_sessions (uid, active, NULL); + + if (status < 0) + nm_log_err (LOGD_CORE, "Failed to get systemd sessions for uid %d: %d", + uid, status); + + return status > 0; +} + +static gboolean +sd_changed (GIOChannel *stream, GIOCondition condition, gpointer user_data) +{ + NMSessionMonitor *monitor = user_data; + + g_signal_emit (monitor, signals[CHANGED], 0); + + sd_login_monitor_flush (monitor->sd.monitor); + + return TRUE; +} + +static void +sd_init (NMSessionMonitor *monitor) +{ + int status; + GIOChannel *stream; + + if (!g_file_test ("/run/systemd/seats/", G_FILE_TEST_EXISTS)) + return; + + if ((status = sd_login_monitor_new (NULL, &monitor->sd.monitor)) < 0) { + nm_log_err (LOGD_CORE, "Failed to create systemd login monitor: %d", status); + return; + } + + stream = g_io_channel_unix_new (sd_login_monitor_get_fd (monitor->sd.monitor)); + monitor->sd.watch = g_io_add_watch (stream, G_IO_IN, sd_changed, monitor); + + g_io_channel_unref (stream); +} + +static void +sd_finalize (NMSessionMonitor *monitor) +{ + g_clear_pointer (&monitor->sd.monitor, sd_login_monitor_unref); + g_source_remove (monitor->sd.watch); +} +#endif /* SESSION_TRACKING_SYSTEMD */ + +/********************************************************************/ + +#ifdef SESSION_TRACKING_CONSOLEKIT +typedef struct { + gboolean active; +} CkSession; + +static gboolean +ck_load_cache (GHashTable *cache) +{ + GKeyFile *keyfile = g_key_file_new (); + char **groups = NULL; + GError *error = NULL; + gsize i, len; + gboolean finished = FALSE; + + if (!g_key_file_load_from_file (keyfile, CKDB_PATH, G_KEY_FILE_NONE, &error)) + goto out; + + if (!(groups = g_key_file_get_groups (keyfile, &len))) { + nm_log_err (LOGD_CORE, "Could not load groups from " CKDB_PATH); + goto out; + } + + g_hash_table_remove_all (cache); + + for (i = 0; i < len; i++) { + guint uid = G_MAXUINT; + CkSession session = { .active = FALSE }; + + if (!g_str_has_prefix (groups[i], "CkSession ")) + continue; + + uid = g_key_file_get_integer (keyfile, groups[i], "uid", &error); + if (error) + goto out; + + session.active = g_key_file_get_boolean (keyfile, groups[i], "is_active", &error); + if (error) + goto out; + + g_hash_table_insert (cache, GUINT_TO_POINTER (uid), g_memdup (&session, sizeof session)); + } + + finished = TRUE; +out: + if (error) + nm_log_err (LOGD_CORE, "ConsoleKit: Failed to load database: %s", error->message); + g_clear_error (&error); + g_clear_pointer (&groups, g_strfreev); + g_clear_pointer (&keyfile, g_key_file_free); + + return finished; +} + +static gboolean +ck_update_cache (NMSessionMonitor *monitor) +{ + struct stat statbuf; + + if (!monitor->ck.cache) + return FALSE; + + /* Check the database file */ + if (stat (CKDB_PATH, &statbuf) != 0) { + nm_log_err (LOGD_CORE, "Failed to check ConsoleKit timestamp: %s", strerror (errno)); + return FALSE; + } + if (statbuf.st_mtime == monitor->ck.timestamp) + return TRUE; + + /* Update the cache */ + if (!ck_load_cache (monitor->ck.cache)) + return FALSE; + + monitor->ck.timestamp = statbuf.st_mtime; + + return TRUE; +} + +static gboolean +ck_session_exists (NMSessionMonitor *monitor, uid_t uid, gboolean active) +{ + CkSession *session; + + if (!ck_update_cache (monitor)) + return FALSE; + + session = g_hash_table_lookup (monitor->ck.cache, GUINT_TO_POINTER (uid)); + + if (!session) + return FALSE; + if (active && !session->active) + return FALSE; + + return TRUE; +} + +static void +ck_changed (GFileMonitor * file_monitor, + GFile * file, + GFile * other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + g_signal_emit (user_data, signals[CHANGED], 0); +} + +static void +ck_init (NMSessionMonitor *monitor) +{ + GFile *file = g_file_new_for_path (CKDB_PATH); + GError *error = NULL; + + if (g_file_query_exists (file, NULL)) { + if ((monitor->ck.monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &error))) { + monitor->ck.cache = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); + g_signal_connect (monitor->ck.monitor, + "changed", + G_CALLBACK (ck_changed), + monitor); + } else { + nm_log_err (LOGD_CORE, "Error monitoring " CKDB_PATH ": %s", error->message); + g_clear_error (&error); + } + } + + g_object_unref (file); +} + +static void +ck_finalize (NMSessionMonitor *monitor) +{ + g_clear_pointer (&monitor->ck.cache, g_hash_table_unref); + g_clear_object (&monitor->ck.monitor); +} +#endif /* SESSION_TRACKING_CONSOLEKIT */ + +/********************************************************************/ + +NM_DEFINE_SINGLETON_GETTER (NMSessionMonitor, nm_session_monitor_get, NM_TYPE_SESSION_MONITOR); + +/** + * nm_session_monitor_connect: + * @self: the session monitor + * @callback: The callback. + * @user_data: User data for the callback. + * + * Connect a callback to the session monitor. + * + * Returns: Handler ID to be used with nm_session_monitor_disconnect(). + */ +gulong +nm_session_monitor_connect (NMSessionMonitor *self, + NMSessionCallback callback, + gpointer user_data) +{ + g_return_val_if_fail (NM_IS_SESSION_MONITOR (self), 0); + + return g_signal_connect (self, + NM_SESSION_MONITOR_CHANGED, + G_CALLBACK (callback), + user_data); +} + +/** + * nm_session_monitor_disconnect: + * @self: the session monitor + * @handler_id: Handler ID returned by nm_session_monitor-connect(). + * + * Disconnect callback from the session handler. + */ +void +nm_session_monitor_disconnect (NMSessionMonitor *self, + gulong handler_id) +{ + g_return_if_fail (NM_IS_SESSION_MONITOR (self)); + + g_signal_handler_disconnect (self, handler_id); +} + +/** + * nm_session_monitor_uid_to_user: + * @uid: UID. + * @out_user: Return location for user name. + * + * Translates a UID to a user name. + */ +gboolean +nm_session_monitor_uid_to_user (uid_t uid, const char **out_user) +{ + struct passwd *pw = getpwuid (uid); + + g_assert (out_user); + + if (!pw) + return FALSE; + + *out_user = pw->pw_name; + + return TRUE; +} + +/** + * nm_session_monitor_user_to_uid: + * @user: User naee. + * @out_uid: Return location for UID. + * + * Translates a user name to a UID. + */ +gboolean +nm_session_monitor_user_to_uid (const char *user, uid_t *out_uid) +{ + struct passwd *pw = getpwnam (user); + + g_assert (out_uid); + + if (!pw) + return FALSE; + + *out_uid = pw->pw_uid; + + return TRUE; +} + +/** + * nm_session_monitor_session_exists: + * @self: the session monitor + * @uid: A user ID. + * @active: Ignore inactive sessions. + * + * Checks whether the given @uid is logged into an active session. Don't + * use this feature for security purposes. It is there just to allow you + * to prefer an agent from an active session over an agent from an + * inactive one. + * + * Returns: %FALSE if @error is set otherwise %TRUE if the given @uid is + * logged into an active session. + */ +gboolean +nm_session_monitor_session_exists (NMSessionMonitor *self, + uid_t uid, + gboolean active) +{ + g_return_val_if_fail (NM_IS_SESSION_MONITOR (self), FALSE); + +#ifdef SESSION_TRACKING_SYSTEMD + if (sd_session_exists (self, uid, active)) + return TRUE; +#endif + +#ifdef SESSION_TRACKING_CONSOLEKIT + if (ck_session_exists (self, uid, active)) + return TRUE; +#endif + + return FALSE; +} + +/********************************************************************/ + +static void +nm_session_monitor_init (NMSessionMonitor *monitor) +{ +#ifdef SESSION_TRACKING_SYSTEMD + sd_init (monitor); +#endif + +#ifdef SESSION_TRACKING_CONSOLEKIT + ck_init (monitor); +#endif +} + +static void +nm_session_monitor_finalize (GObject *object) +{ +#ifdef SESSION_TRACKING_SYSTEMD + sd_finalize (NM_SESSION_MONITOR (object)); +#endif + +#ifdef SESSION_TRACKING_CONSOLEKIT + ck_finalize (NM_SESSION_MONITOR (object)); +#endif + + if (G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize != NULL) + G_OBJECT_CLASS (nm_session_monitor_parent_class)->finalize (object); +} + +static void +nm_session_monitor_class_init (NMSessionMonitorClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = nm_session_monitor_finalize; + + /** + * NMSessionMonitor::changed: + * @monitor: A #NMSessionMonitor + * + * Emitted when something changes. + */ + signals[CHANGED] = g_signal_new (NM_SESSION_MONITOR_CHANGED, + NM_TYPE_SESSION_MONITOR, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMSessionMonitorClass, changed), + NULL, /* accumulator */ + NULL, /* accumulator data */ + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} diff --git a/src/nm-session-monitor.h b/src/nm-session-monitor.h index 3efe6eca..af50b71b 100644 --- a/src/nm-session-monitor.h +++ b/src/nm-session-monitor.h @@ -21,9 +21,8 @@ #ifndef __NETWORKMANAGER_SESSION_MONITOR_H__ #define __NETWORKMANAGER_SESSION_MONITOR_H__ -#include -#include "nm-types.h" +#include "nm-default.h" G_BEGIN_DECLS @@ -38,26 +37,23 @@ G_BEGIN_DECLS typedef struct _NMSessionMonitorClass NMSessionMonitorClass; -GType nm_session_monitor_get_type (void) G_GNUC_CONST; -NMSessionMonitor *nm_session_monitor_get (void); +typedef void (*NMSessionCallback) (NMSessionMonitor *monitor, gpointer user_data); -gboolean nm_session_monitor_user_has_session (NMSessionMonitor *monitor, - const char *username, - uid_t *out_uid, - GError **error); +GType nm_session_monitor_get_type (void) G_GNUC_CONST; -gboolean nm_session_monitor_uid_has_session (NMSessionMonitor *monitor, - uid_t uid, - const char **out_user, - GError **error); +NMSessionMonitor *nm_session_monitor_get (void); -gboolean nm_session_monitor_user_active (NMSessionMonitor *monitor, - const char *username, - GError **error); +gulong nm_session_monitor_connect (NMSessionMonitor *self, + NMSessionCallback callback, + gpointer user_data); +void nm_session_monitor_disconnect (NMSessionMonitor *self, + gulong handler_id); -gboolean nm_session_monitor_uid_active (NMSessionMonitor *monitor, - uid_t uid, - GError **error); +gboolean nm_session_monitor_uid_to_user (uid_t uid, const char **out_user); +gboolean nm_session_monitor_user_to_uid (const char *user, uid_t *out_uid); +gboolean nm_session_monitor_session_exists (NMSessionMonitor *self, + uid_t uid, + gboolean active); G_END_DECLS diff --git a/src/nm-session-utils.c b/src/nm-session-utils.c deleted file mode 100644 index eb156fad..00000000 --- a/src/nm-session-utils.c +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* 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) 2012 Red Hat, Inc. - * Author: Dan Williams - */ - -#include "config.h" - -#include -#include - -#include "nm-session-utils.h" -#include "nm-errors.h" - -/********************************************************************/ - -gboolean -nm_session_uid_to_user (uid_t uid, const char **out_user, GError **error) -{ - struct passwd *pw; - - pw = getpwuid (uid); - if (!pw) { - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Could not get username for UID %d", - uid); - return FALSE; - } - - if (out_user) - *out_user = pw->pw_name; - return TRUE; -} - -gboolean -nm_session_user_to_uid (const char *user, uid_t *out_uid, GError **error) -{ - struct passwd *pw; - - pw = getpwnam (user); - if (!pw) { - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "Could not get UID for username '%s'", - user); - return FALSE; - } - - /* Ugly, but hey, use ConsoleKit */ - if (out_uid) - *out_uid = pw->pw_uid; - return TRUE; -} - diff --git a/src/nm-session-utils.h b/src/nm-session-utils.h deleted file mode 100644 index e626f52a..00000000 --- a/src/nm-session-utils.h +++ /dev/null @@ -1,30 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* 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) 2012 Red Hat, Inc. - * Author: Dan Williams - */ - -#ifndef __NETWORKMANAGER_SESSION_UTILS_H__ -#define __NETWORKMANAGER_SESSION_UTILS_H__ - -#include -#include - -gboolean nm_session_uid_to_user (uid_t uid, const char **out_user, GError **error); - -gboolean nm_session_user_to_uid (const char *user, uid_t *out_uid, GError **error); - -#endif /* NM_SESSION_UTILS_H */ diff --git a/src/nm-settings-connection-glue.h b/src/nm-settings-connection-glue.h deleted file mode 100644 index 22f096c6..00000000 --- a/src/nm-settings-connection-glue.h +++ /dev/null @@ -1,172 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_settings_connection_MARSHAL_H__ -#define __dbus_glib_marshal_nm_settings_connection_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -/* NONE:POINTER */ -#define dbus_glib_marshal_nm_settings_connection_VOID__POINTER g_cclosure_marshal_VOID__POINTER -#define dbus_glib_marshal_nm_settings_connection_NONE__POINTER dbus_glib_marshal_nm_settings_connection_VOID__POINTER - -/* NONE:STRING,POINTER */ -extern void dbus_glib_marshal_nm_settings_connection_VOID__STRING_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_settings_connection_VOID__STRING_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__STRING_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer data2); - GMarshalFunc_VOID__STRING_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_VOID__STRING_POINTER) (marshal_data ? marshal_data : cc->callback); - - callback (data1, - g_marshal_value_peek_string (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - data2); -} -#define dbus_glib_marshal_nm_settings_connection_NONE__STRING_POINTER dbus_glib_marshal_nm_settings_connection_VOID__STRING_POINTER - -/* NONE:BOXED,POINTER */ -extern void dbus_glib_marshal_nm_settings_connection_VOID__BOXED_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_settings_connection_VOID__BOXED_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__BOXED_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer data2); - GMarshalFunc_VOID__BOXED_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_VOID__BOXED_POINTER) (marshal_data ? marshal_data : cc->callback); - - callback (data1, - g_marshal_value_peek_boxed (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - data2); -} -#define dbus_glib_marshal_nm_settings_connection_NONE__BOXED_POINTER dbus_glib_marshal_nm_settings_connection_VOID__BOXED_POINTER - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_settings_connection_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_settings_connection_methods[] = { - { (GCallback) impl_settings_connection_update, dbus_glib_marshal_nm_settings_connection_NONE__BOXED_POINTER, 0 }, - { (GCallback) impl_settings_connection_update_unsaved, dbus_glib_marshal_nm_settings_connection_NONE__BOXED_POINTER, 84 }, - { (GCallback) impl_settings_connection_delete, dbus_glib_marshal_nm_settings_connection_NONE__POINTER, 175 }, - { (GCallback) impl_settings_connection_get_settings, dbus_glib_marshal_nm_settings_connection_NONE__POINTER, 236 }, - { (GCallback) impl_settings_connection_get_secrets, dbus_glib_marshal_nm_settings_connection_NONE__STRING_POINTER, 327 }, - { (GCallback) impl_settings_connection_clear_secrets, dbus_glib_marshal_nm_settings_connection_NONE__POINTER, 433 }, - { (GCallback) impl_settings_connection_save, dbus_glib_marshal_nm_settings_connection_NONE__POINTER, 500 }, -}; - -const DBusGObjectInfo dbus_glib_nm_settings_connection_object_info = { 1, - dbus_glib_nm_settings_connection_methods, - 7, -"org.freedesktop.NetworkManager.Settings.Connection\0Update\0A\0properties\0I\0a{sa{sv}}\0\0org.freedesktop.NetworkManager.Settings.Connection\0UpdateUnsaved\0A\0properties\0I\0a{sa{sv}}\0\0org.freedesktop.NetworkManager.Settings.Connection\0Delete\0A\0\0org.freedesktop.NetworkManager.Settings.Connection\0GetSettings\0A\0settings\0O\0F\0N\0a{sa{sv}}\0\0org.freedesktop.NetworkManager.Settings.Connection\0GetSecrets\0A\0setting_name\0I\0s\0secrets\0O\0F\0N\0a{sa{sv}}\0\0org.freedesktop.NetworkManager.Settings.Connection\0ClearSecrets\0A\0\0org.freedesktop.NetworkManager.Settings.Connection\0Save\0A\0\0\0", -"org.freedesktop.NetworkManager.Settings.Connection\0Updated\0org.freedesktop.NetworkManager.Settings.Connection\0Removed\0org.freedesktop.NetworkManager.Settings.Connection\0PropertiesChanged\0\0", -"org.freedesktop.NetworkManager.Settings.Connection\0Unsaved\0unsaved\0read\0\0" -}; - diff --git a/src/nm-settings-glue.h b/src/nm-settings-glue.h deleted file mode 100644 index d03c4545..00000000 --- a/src/nm-settings-glue.h +++ /dev/null @@ -1,219 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_settings_MARSHAL_H__ -#define __dbus_glib_marshal_nm_settings_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -/* NONE:POINTER */ -#define dbus_glib_marshal_nm_settings_VOID__POINTER g_cclosure_marshal_VOID__POINTER -#define dbus_glib_marshal_nm_settings_NONE__POINTER dbus_glib_marshal_nm_settings_VOID__POINTER - -/* BOOLEAN:POINTER,POINTER */ -extern void dbus_glib_marshal_nm_settings_BOOLEAN__POINTER_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_settings_BOOLEAN__POINTER_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef gboolean (*GMarshalFunc_BOOLEAN__POINTER_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer data2); - GMarshalFunc_BOOLEAN__POINTER_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - gboolean v_return; - - g_return_if_fail (return_value != NULL); - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_BOOLEAN__POINTER_POINTER) (marshal_data ? marshal_data : cc->callback); - - v_return = callback (data1, - g_marshal_value_peek_pointer (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - data2); - - g_value_set_boolean (return_value, v_return); -} - -/* NONE:STRING,POINTER */ -extern void dbus_glib_marshal_nm_settings_VOID__STRING_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_settings_VOID__STRING_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__STRING_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer data2); - GMarshalFunc_VOID__STRING_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_VOID__STRING_POINTER) (marshal_data ? marshal_data : cc->callback); - - callback (data1, - g_marshal_value_peek_string (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - data2); -} -#define dbus_glib_marshal_nm_settings_NONE__STRING_POINTER dbus_glib_marshal_nm_settings_VOID__STRING_POINTER - -/* NONE:BOXED,POINTER */ -extern void dbus_glib_marshal_nm_settings_VOID__BOXED_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); -void -dbus_glib_marshal_nm_settings_VOID__BOXED_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__BOXED_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer data2); - GMarshalFunc_VOID__BOXED_POINTER callback; - GCClosure *cc = (GCClosure*) closure; - gpointer data1, data2; - - g_return_if_fail (n_param_values == 3); - - if (G_CCLOSURE_SWAP_DATA (closure)) - { - data1 = closure->data; - data2 = g_value_peek_pointer (param_values + 0); - } - else - { - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - } - callback = (GMarshalFunc_VOID__BOXED_POINTER) (marshal_data ? marshal_data : cc->callback); - - callback (data1, - g_marshal_value_peek_boxed (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), - data2); -} -#define dbus_glib_marshal_nm_settings_NONE__BOXED_POINTER dbus_glib_marshal_nm_settings_VOID__BOXED_POINTER - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_settings_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_settings_methods[] = { - { (GCallback) impl_settings_list_connections, dbus_glib_marshal_nm_settings_BOOLEAN__POINTER_POINTER, 0 }, - { (GCallback) impl_settings_get_connection_by_uuid, dbus_glib_marshal_nm_settings_NONE__STRING_POINTER, 80 }, - { (GCallback) impl_settings_add_connection, dbus_glib_marshal_nm_settings_NONE__BOXED_POINTER, 171 }, - { (GCallback) impl_settings_add_connection_unsaved, dbus_glib_marshal_nm_settings_NONE__BOXED_POINTER, 264 }, - { (GCallback) impl_settings_load_connections, dbus_glib_marshal_nm_settings_NONE__BOXED_POINTER, 364 }, - { (GCallback) impl_settings_reload_connections, dbus_glib_marshal_nm_settings_NONE__POINTER, 471 }, - { (GCallback) impl_settings_save_hostname, dbus_glib_marshal_nm_settings_NONE__STRING_POINTER, 547 }, -}; - -const DBusGObjectInfo dbus_glib_nm_settings_object_info = { 1, - dbus_glib_nm_settings_methods, - 7, -"org.freedesktop.NetworkManager.Settings\0ListConnections\0S\0connections\0O\0F\0N\0ao\0\0org.freedesktop.NetworkManager.Settings\0GetConnectionByUuid\0A\0uuid\0I\0s\0connection\0O\0F\0N\0o\0\0org.freedesktop.NetworkManager.Settings\0AddConnection\0A\0connection\0I\0a{sa{sv}}\0path\0O\0F\0N\0o\0\0org.freedesktop.NetworkManager.Settings\0AddConnectionUnsaved\0A\0connection\0I\0a{sa{sv}}\0path\0O\0F\0N\0o\0\0org.freedesktop.NetworkManager.Settings\0LoadConnections\0A\0filenames\0I\0as\0status\0O\0F\0N\0b\0failures\0O\0F\0N\0as\0\0org.freedesktop.NetworkManager.Settings\0ReloadConnections\0A\0status\0O\0F\0N\0b\0\0org.freedesktop.NetworkManager.Settings\0SaveHostname\0A\0hostname\0I\0s\0\0\0", -"org.freedesktop.NetworkManager.Settings\0PropertiesChanged\0org.freedesktop.NetworkManager.Settings\0NewConnection\0org.freedesktop.NetworkManager.Settings\0ConnectionRemoved\0\0", -"org.freedesktop.NetworkManager.Settings\0Connections\0connections\0read\0org.freedesktop.NetworkManager.Settings\0Hostname\0hostname\0read\0org.freedesktop.NetworkManager.Settings\0CanModify\0can_modify\0read\0\0" -}; - diff --git a/src/nm-sleep-monitor-systemd.c b/src/nm-sleep-monitor-systemd.c index 44523a4a..12db56b2 100644 --- a/src/nm-sleep-monitor-systemd.c +++ b/src/nm-sleep-monitor-systemd.c @@ -22,19 +22,35 @@ #include #include #include -#include -#include #include -#include "nm-logging.h" -#include "nm-dbus-manager.h" +#include "nm-default.h" +#include "nm-core-internal.h" +#include "NetworkManagerUtils.h" #include "nm-sleep-monitor.h" -#define SD_NAME "org.freedesktop.login1" -#define SD_PATH "/org/freedesktop/login1" -#define SD_INTERFACE "org.freedesktop.login1.Manager" +#if defined (SUSPEND_RESUME_SYSTEMD) == defined (SUSPEND_RESUME_CONSOLEKIT) +#error either define SUSPEND_RESUME_SYSTEMD or SUSPEND_RESUME_CONSOLEKIT +#endif +#ifdef SUSPEND_RESUME_SYSTEMD + +#define SUSPEND_DBUS_NAME "org.freedesktop.login1" +#define SUSPEND_DBUS_PATH "/org/freedesktop/login1" +#define SUSPEND_DBUS_INTERFACE "org.freedesktop.login1.Manager" + +#else + +/* ConsoleKit2 has added the same suspend/resume DBUS API that Systemd + * uses. http://consolekit2.github.io/ConsoleKit2/#Manager.Inhibit + */ + +#define SUSPEND_DBUS_NAME "org.freedesktop.ConsoleKit" +#define SUSPEND_DBUS_PATH "/org/freedesktop/ConsoleKit/Manager" +#define SUSPEND_DBUS_INTERFACE "org.freedesktop.ConsoleKit.Manager" + +#endif struct _NMSleepMonitor { GObject parent_instance; @@ -87,6 +103,7 @@ inhibit_done (GObject *source, res = g_dbus_proxy_call_with_unix_fd_list_finish (sd_proxy, &fd_list, result, &error); if (!res) { + g_dbus_error_strip_remote_error (error); nm_log_warn (LOGD_SUSPEND, "Inhibit failed: %s", error->message); g_error_free (error); } else { @@ -123,19 +140,12 @@ take_inhibitor (NMSleepMonitor *self) } static void -signal_cb (GDBusProxy *proxy, - const gchar *sendername, - const gchar *signalname, - GVariant *args, - gpointer data) +prepare_for_sleep_cb (GDBusProxy *proxy, + gboolean is_about_to_suspend, + gpointer data) { NMSleepMonitor *self = data; - gboolean is_about_to_suspend; - - if (strcmp (signalname, "PrepareForSleep") != 0) - return; - g_variant_get (args, "(b)", &is_about_to_suspend); nm_log_dbg (LOGD_SUSPEND, "Received PrepareForSleep signal: %d", is_about_to_suspend); if (is_about_to_suspend) { @@ -182,7 +192,8 @@ on_proxy_acquired (GObject *object, } g_signal_connect (self->sd_proxy, "notify::g-name-owner", G_CALLBACK (name_owner_cb), self); - g_signal_connect (self->sd_proxy, "g-signal", G_CALLBACK (signal_cb), self); + _nm_dbus_signal_connect (self->sd_proxy, "PrepareForSleep", G_VARIANT_TYPE ("(b)"), + G_CALLBACK (prepare_for_sleep_cb), self); owner = g_dbus_proxy_get_name_owner (self->sd_proxy); if (owner) @@ -198,7 +209,7 @@ nm_sleep_monitor_init (NMSleepMonitor *self) G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, NULL, - SD_NAME, SD_PATH, SD_INTERFACE, + SUSPEND_DBUS_NAME, SUSPEND_DBUS_PATH, SUSPEND_DBUS_INTERFACE, NULL, (GAsyncReadyCallback) on_proxy_acquired, self); } diff --git a/src/nm-sleep-monitor-upower.c b/src/nm-sleep-monitor-upower.c index 0c46ae10..c65609cf 100644 --- a/src/nm-sleep-monitor-upower.c +++ b/src/nm-sleep-monitor-upower.c @@ -22,33 +22,31 @@ #include #include #include -#include -#include -#include "nm-logging.h" -#include "nm-dbus-manager.h" +#include "nm-default.h" +#include "nm-core-internal.h" #include "nm-sleep-monitor.h" #define UPOWER_DBUS_SERVICE "org.freedesktop.UPower" struct _NMSleepMonitor { - GObject parent_instance; + GObject parent_instance; - DBusGProxy *upower_proxy; + GDBusProxy *upower_proxy; }; struct _NMSleepMonitorClass { - GObjectClass parent_class; + GObjectClass parent_class; - void (*sleeping) (NMSleepMonitor *monitor); - void (*resuming) (NMSleepMonitor *monitor); + void (*sleeping) (NMSleepMonitor *monitor); + void (*resuming) (NMSleepMonitor *monitor); }; enum { - SLEEPING, - RESUMING, - LAST_SIGNAL, + SLEEPING, + RESUMING, + LAST_SIGNAL, }; static guint signals[LAST_SIGNAL] = {0}; @@ -57,80 +55,78 @@ G_DEFINE_TYPE (NMSleepMonitor, nm_sleep_monitor, G_TYPE_OBJECT); /********************************************************************/ static void -upower_sleeping_cb (DBusGProxy *proxy, gpointer user_data) +upower_sleeping_cb (GDBusProxy *proxy, gpointer user_data) { - nm_log_dbg (LOGD_SUSPEND, "Received UPower sleeping signal"); - g_signal_emit (user_data, signals[SLEEPING], 0); + nm_log_dbg (LOGD_SUSPEND, "Received UPower sleeping signal"); + g_signal_emit (user_data, signals[SLEEPING], 0); } static void -upower_resuming_cb (DBusGProxy *proxy, gpointer user_data) +upower_resuming_cb (GDBusProxy *proxy, gpointer user_data) { - nm_log_dbg (LOGD_SUSPEND, "Received UPower resuming signal"); - g_signal_emit (user_data, signals[RESUMING], 0); + nm_log_dbg (LOGD_SUSPEND, "Received UPower resuming signal"); + g_signal_emit (user_data, signals[RESUMING], 0); } static void nm_sleep_monitor_init (NMSleepMonitor *self) { - DBusGConnection *bus; - - bus = nm_dbus_manager_get_connection (nm_dbus_manager_get ()); - self->upower_proxy = dbus_g_proxy_new_for_name (bus, - UPOWER_DBUS_SERVICE, - "/org/freedesktop/UPower", - "org.freedesktop.UPower"); - if (self->upower_proxy) { - dbus_g_proxy_add_signal (self->upower_proxy, "Sleeping", G_TYPE_INVALID); - dbus_g_proxy_connect_signal (self->upower_proxy, "Sleeping", - G_CALLBACK (upower_sleeping_cb), - self, NULL); - - dbus_g_proxy_add_signal (self->upower_proxy, "Resuming", G_TYPE_INVALID); - dbus_g_proxy_connect_signal (self->upower_proxy, "Resuming", - G_CALLBACK (upower_resuming_cb), - self, NULL); - } else - nm_log_warn (LOGD_SUSPEND, "could not initialize UPower D-Bus proxy"); + GError *error = NULL; + + self->upower_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START | + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, + UPOWER_DBUS_SERVICE, + "/org/freedesktop/UPower", + "org.freedesktop.UPower", + NULL, &error); + if (self->upower_proxy) { + _nm_dbus_signal_connect (self->upower_proxy, "Sleeping", NULL, + G_CALLBACK (upower_sleeping_cb), self); + _nm_dbus_signal_connect (self->upower_proxy, "Resuming", NULL, + G_CALLBACK (upower_resuming_cb), self); + } else { + nm_log_warn (LOGD_SUSPEND, "could not initialize UPower D-Bus proxy: %s", error->message); + g_error_free (error); + } } static void finalize (GObject *object) { - NMSleepMonitor *self = NM_SLEEP_MONITOR (object); + NMSleepMonitor *self = NM_SLEEP_MONITOR (object); - if (self->upower_proxy) - g_object_unref (self->upower_proxy); + g_clear_object (&self->upower_proxy); - if (G_OBJECT_CLASS (nm_sleep_monitor_parent_class)->finalize != NULL) - G_OBJECT_CLASS (nm_sleep_monitor_parent_class)->finalize (object); + G_OBJECT_CLASS (nm_sleep_monitor_parent_class)->finalize (object); } static void nm_sleep_monitor_class_init (NMSleepMonitorClass *klass) { - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->finalize = finalize; - - signals[SLEEPING] = g_signal_new (NM_SLEEP_MONITOR_SLEEPING, - NM_TYPE_SLEEP_MONITOR, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMSleepMonitorClass, sleeping), - NULL, /* accumulator */ - NULL, /* accumulator data */ - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - signals[RESUMING] = g_signal_new (NM_SLEEP_MONITOR_RESUMING, - NM_TYPE_SLEEP_MONITOR, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMSleepMonitorClass, resuming), - NULL, /* accumulator */ - NULL, /* accumulator data */ - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = finalize; + + signals[SLEEPING] = g_signal_new (NM_SLEEP_MONITOR_SLEEPING, + NM_TYPE_SLEEP_MONITOR, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMSleepMonitorClass, sleeping), + NULL, /* accumulator */ + NULL, /* accumulator data */ + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals[RESUMING] = g_signal_new (NM_SLEEP_MONITOR_RESUMING, + NM_TYPE_SLEEP_MONITOR, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMSleepMonitorClass, resuming), + NULL, /* accumulator */ + NULL, /* accumulator data */ + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } NM_DEFINE_SINGLETON_GETTER (NMSleepMonitor, nm_sleep_monitor_get, NM_TYPE_SLEEP_MONITOR); diff --git a/src/nm-sleep-monitor.h b/src/nm-sleep-monitor.h index 84623771..21e6b844 100644 --- a/src/nm-sleep-monitor.h +++ b/src/nm-sleep-monitor.h @@ -20,9 +20,8 @@ #ifndef __NETWORKMANAGER_SLEEP_MONITOR_H__ #define __NETWORKMANAGER_SLEEP_MONITOR_H__ -#include -#include "nm-types.h" +#include "nm-default.h" G_BEGIN_DECLS diff --git a/src/nm-types.h b/src/nm-types.h index 5806e15d..7934fcbb 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -21,16 +21,22 @@ #ifndef __NETWORKMANAGER_TYPES_H__ #define __NETWORKMANAGER_TYPES_H__ +#ifdef __NM_UTILS_PRIVATE_H__ +#error "nm-utils-private.h" must not be used outside of libnm-core/. Do you want "nm-core-internal.h"? +#endif + /* core */ +typedef struct _NMExportedObject NMExportedObject; typedef struct _NMActiveConnection NMActiveConnection; +typedef struct _NMAuditManager NMAuditManager; typedef struct _NMVpnConnection NMVpnConnection; typedef struct _NMActRequest NMActRequest; typedef struct _NMAuthSubject NMAuthSubject; +typedef struct _NMBusManager NMBusManager; typedef struct _NMConfig NMConfig; typedef struct _NMConfigData NMConfigData; typedef struct _NMConnectionProvider NMConnectionProvider; typedef struct _NMConnectivity NMConnectivity; -typedef struct _NMDBusManager NMDBusManager; typedef struct _NMDefaultRouteManager NMDefaultRouteManager; typedef struct _NMDevice NMDevice; typedef struct _NMDhcp4Config NMDhcp4Config; @@ -43,6 +49,7 @@ typedef struct _NMRfkillManager NMRfkillManager; typedef struct _NMRouteManager NMRouteManager; typedef struct _NMSessionMonitor NMSessionMonitor; typedef struct _NMSleepMonitor NMSleepMonitor; +typedef struct _NMLldpListener NMLldpListener; typedef enum { /* In priority order; higher number == higher priority */ @@ -72,6 +79,8 @@ typedef struct _NMPlatformIP6Address NMPlatformIP6Address; typedef struct _NMPlatformIP6Route NMPlatformIP6Route; typedef struct _NMPlatformLink NMPlatformLink; +typedef struct _NMPObject NMPObject; + 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(). @@ -99,10 +108,13 @@ typedef enum { NM_LINK_TYPE_GRE, NM_LINK_TYPE_GRETAP, NM_LINK_TYPE_IFB, + NM_LINK_TYPE_IP6TNL, + NM_LINK_TYPE_IPIP, NM_LINK_TYPE_LOOPBACK, NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP, NM_LINK_TYPE_OPENVSWITCH, + NM_LINK_TYPE_SIT, NM_LINK_TYPE_TAP, NM_LINK_TYPE_TUN, NM_LINK_TYPE_VETH, @@ -114,6 +126,8 @@ typedef enum { NM_LINK_TYPE_BRIDGE = 0x10000 | 0x20000, NM_LINK_TYPE_BOND, NM_LINK_TYPE_TEAM, + + NM_LINK_TYPE_ANY = G_MAXUINT32, } NMLinkType; typedef enum { @@ -123,6 +137,17 @@ typedef enum { NMP_OBJECT_TYPE_IP6_ADDRESS, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE, + + NMP_OBJECT_TYPE_LNK_GRE, + NMP_OBJECT_TYPE_LNK_INFINIBAND, + NMP_OBJECT_TYPE_LNK_IP6TNL, + NMP_OBJECT_TYPE_LNK_IPIP, + NMP_OBJECT_TYPE_LNK_MACVLAN, + NMP_OBJECT_TYPE_LNK_MACVTAP, + NMP_OBJECT_TYPE_LNK_SIT, + NMP_OBJECT_TYPE_LNK_VLAN, + NMP_OBJECT_TYPE_LNK_VXLAN, + __NMP_OBJECT_TYPE_LAST, NMP_OBJECT_TYPE_MAX = __NMP_OBJECT_TYPE_LAST - 1, } NMPObjectType; diff --git a/src/nm-vpn-connection-glue.h b/src/nm-vpn-connection-glue.h deleted file mode 100644 index 74b8c7dc..00000000 --- a/src/nm-vpn-connection-glue.h +++ /dev/null @@ -1,73 +0,0 @@ -/* Generated by dbus-binding-tool; do not edit! */ - - -#ifndef __dbus_glib_marshal_nm_vpn_connection_MARSHAL_H__ -#define __dbus_glib_marshal_nm_vpn_connection_MARSHAL_H__ - -#include - -G_BEGIN_DECLS - -#ifdef G_ENABLE_DEBUG -#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_schar (v) -#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) -#define g_marshal_value_peek_int(v) g_value_get_int (v) -#define g_marshal_value_peek_uint(v) g_value_get_uint (v) -#define g_marshal_value_peek_long(v) g_value_get_long (v) -#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v) -#define g_marshal_value_peek_int64(v) g_value_get_int64 (v) -#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v) -#define g_marshal_value_peek_enum(v) g_value_get_enum (v) -#define g_marshal_value_peek_flags(v) g_value_get_flags (v) -#define g_marshal_value_peek_float(v) g_value_get_float (v) -#define g_marshal_value_peek_double(v) g_value_get_double (v) -#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v) -#define g_marshal_value_peek_param(v) g_value_get_param (v) -#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v) -#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v) -#define g_marshal_value_peek_object(v) g_value_get_object (v) -#define g_marshal_value_peek_variant(v) g_value_get_variant (v) -#else /* !G_ENABLE_DEBUG */ -/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API. - * Do not access GValues directly in your code. Instead, use the - * g_value_get_*() functions - */ -#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int -#define g_marshal_value_peek_char(v) (v)->data[0].v_int -#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint -#define g_marshal_value_peek_int(v) (v)->data[0].v_int -#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint -#define g_marshal_value_peek_long(v) (v)->data[0].v_long -#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64 -#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64 -#define g_marshal_value_peek_enum(v) (v)->data[0].v_long -#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong -#define g_marshal_value_peek_float(v) (v)->data[0].v_float -#define g_marshal_value_peek_double(v) (v)->data[0].v_double -#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer -#define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer -#endif /* !G_ENABLE_DEBUG */ - - -G_END_DECLS - -#endif /* __dbus_glib_marshal_nm_vpn_connection_MARSHAL_H__ */ - -#include -static const DBusGMethodInfo dbus_glib_nm_vpn_connection_methods[] = { -}; - -const DBusGObjectInfo dbus_glib_nm_vpn_connection_object_info = { 1, - dbus_glib_nm_vpn_connection_methods, - 0, -"\0", -"org.freedesktop.NetworkManager.VPN.Connection\0PropertiesChanged\0org.freedesktop.NetworkManager.VPN.Connection\0VpnStateChanged\0\0", -"org.freedesktop.NetworkManager.VPN.Connection\0VpnState\0vpn_state\0read\0org.freedesktop.NetworkManager.VPN.Connection\0Banner\0banner\0read\0\0" -}; - diff --git a/src/org.freedesktop.NetworkManager.conf b/src/org.freedesktop.NetworkManager.conf index 10c6184e..801d9a7d 100644 --- a/src/org.freedesktop.NetworkManager.conf +++ b/src/org.freedesktop.NetworkManager.conf @@ -10,13 +10,9 @@ send_interface="org.freedesktop.NetworkManager.PPP"/> - - @@ -29,6 +25,7 @@ + @@ -40,6 +37,8 @@ send_interface="org.freedesktop.DBus.Introspectable"/> + - - 1024 + 2048 diff --git a/src/platform/Makefile.in b/src/platform/Makefile.in index e8b73294..854c6712 100644 --- a/src/platform/Makefile.in +++ b/src/platform/Makefile.in @@ -206,7 +206,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -218,8 +217,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -229,6 +226,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -283,16 +281,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -329,6 +324,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -357,7 +354,6 @@ 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@ @@ -372,6 +368,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -432,6 +430,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -439,6 +438,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index d5aeb030..a4eae902 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -26,15 +26,41 @@ #include #include -#include "gsystem-local-alloc.h" #include "nm-utils.h" +#include "nmp-object.h" #include "NetworkManagerUtils.h" #include "nm-fake-platform.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-test-utils.h" -#define debug(format, ...) nm_log_dbg (LOGD_PLATFORM, format, __VA_ARGS__) +/*********************************************************************************************/ + +#define _NMLOG_PREFIX_NAME "platform-fake" +#define _NMLOG_DOMAIN LOGD_PLATFORM +#define _NMLOG(level, ...) _LOG(level, _NMLOG_DOMAIN, platform, __VA_ARGS__) + +#define _LOG(level, domain, self, ...) \ + G_STMT_START { \ + const NMLogLevel __level = (level); \ + const NMLogDomain __domain = (domain); \ + \ + if (nm_logging_enabled (__level, __domain)) { \ + char __prefix[32]; \ + const char *__p_prefix = _NMLOG_PREFIX_NAME; \ + const void *const __self = (self); \ + \ + if (__self && __self != nm_platform_try_get ()) { \ + g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \ + __p_prefix = __prefix; \ + } \ + _nm_log (__level, __domain, 0, \ + "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } \ + } G_STMT_END + +/*********************************************************************************************/ typedef struct { GHashTable *options; @@ -49,8 +75,7 @@ typedef struct { NMPlatformLink link; char *udi; - int vlan_id; - int ib_p_key; + NMPObject *lnk; struct in6_addr ip6_lladdr; } NMFakePlatformLink; @@ -62,13 +87,26 @@ G_DEFINE_TYPE (NMFakePlatform, nm_fake_platform, NM_TYPE_PLATFORM) static void link_changed (NMPlatform *platform, NMFakePlatformLink *device, gboolean raise_signal); -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); +static gboolean ip6_address_add (NMPlatform *platform, + int ifindex, + struct in6_addr addr, + int plen, + struct in6_addr peer_addr, + guint32 lifetime, + guint32 preferred, + guint flags); static gboolean ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen); /******************************************************************/ +static gboolean +_ip4_address_equal_peer_net (in_addr_t peer1, in_addr_t peer2, int plen) +{ + return ((peer1 ^ peer2) & nm_utils_ip4_prefix_to_netmask (plen)) == 0; +} + +/******************************************************************/ + static gboolean sysctl_set (NMPlatform *platform, const char *path, const char *value) { @@ -157,7 +195,7 @@ link_get (NMPlatform *platform, int ifindex) return device; not_found: - debug ("link not found: %d", ifindex); + _LOGD ("link not found: %d", ifindex); return NULL; } @@ -222,29 +260,63 @@ _nm_platform_link_get_by_address (NMPlatform *platform, return NULL; } +static const NMPObject * +link_get_lnk (NMPlatform *platform, + int ifindex, + NMLinkType link_type, + const NMPlatformLink **out_link) +{ + NMFakePlatformLink *device = link_get (platform, ifindex); + + if (!device) + return NULL; + + NM_SET_OUT (out_link, &device->link); + + if (!device->lnk) + return NULL; + + if (link_type == NM_LINK_TYPE_NONE) + return device->lnk; + + if ( link_type != device->link.type + || link_type != NMP_OBJECT_GET_CLASS (device->lnk)->lnk_link_type) + return NULL; + + return device->lnk; +} + static gboolean link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *address, size_t address_len, - NMPlatformLink *out_link) + const NMPlatformLink **out_link) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMFakePlatformLink device; + NMFakePlatformLink *new_device; link_init (&device, priv->links->len, type, name); + if (address) { + g_return_val_if_fail (address_len > 0 && address_len <= sizeof (device.link.addr.data), FALSE); + memcpy (device.link.addr.data, address, address_len); + device.link.addr.len = address_len; + } + g_array_append_val (priv->links, device); + new_device = &g_array_index (priv->links, NMFakePlatformLink, priv->links->len - 1); if (device.link.ifindex) { - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, NMP_OBJECT_TYPE_LINK, device.link.ifindex, &device, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, NMP_OBJECT_TYPE_LINK, device.link.ifindex, &device, NM_PLATFORM_SIGNAL_ADDED); link_changed (platform, &g_array_index (priv->links, NMFakePlatformLink, priv->links->len - 1), FALSE); } if (out_link) - *out_link = device.link; + *out_link = &new_device->link; return TRUE; } @@ -261,6 +333,8 @@ link_delete (NMPlatform *platform, int ifindex) memcpy (&deleted_device, &device->link, sizeof (deleted_device)); memset (&device->link, 0, sizeof (device->link)); + g_clear_pointer (&device->lnk, nmp_object_unref); + g_clear_pointer (&device->udi, g_free); /* Remove addresses and routes which belong to the deleted interface */ for (i = 0; i < priv->ip4_addresses->len; i++) { @@ -288,7 +362,7 @@ link_delete (NMPlatform *platform, int ifindex) memset (route, 0, sizeof (*route)); } - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, NMP_OBJECT_TYPE_LINK, ifindex, &deleted_device, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_INTERNAL); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, NMP_OBJECT_TYPE_LINK, ifindex, &deleted_device, NM_PLATFORM_SIGNAL_REMOVED); return TRUE; } @@ -306,11 +380,11 @@ link_changed (NMPlatform *platform, NMFakePlatformLink *device, gboolean raise_s int i; if (raise_signal) - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, NMP_OBJECT_TYPE_LINK, device->link.ifindex, &device->link, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, NMP_OBJECT_TYPE_LINK, device->link.ifindex, &device->link, NM_PLATFORM_SIGNAL_CHANGED); if (device->link.ifindex && !IN6_IS_ADDR_UNSPECIFIED (&device->ip6_lladdr)) { if (device->link.connected) - ip6_address_add (platform, device->link.ifindex, device->ip6_lladdr, in6addr_any, 64, NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0); + ip6_address_add (platform, device->link.ifindex, in6addr_any, 64, device->ip6_lladdr, NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0); else ip6_address_delete (platform, device->link.ifindex, device->ip6_lladdr, 64); } @@ -345,8 +419,10 @@ link_set_up (NMPlatform *platform, int ifindex, gboolean *out_no_firmware) if (out_no_firmware) *out_no_firmware = FALSE; - if (!device) + if (!device) { + _LOGE ("failure changing link: netlink error (No such device)"); return FALSE; + } up = TRUE; connected = TRUE; @@ -379,8 +455,10 @@ link_set_down (NMPlatform *platform, int ifindex) { NMFakePlatformLink *device = link_get (platform, ifindex); - if (!device) + if (!device) { + _LOGE ("failure changing link: netlink error (No such device)"); return FALSE; + } if (NM_FLAGS_HAS (device->link.flags, IFF_UP) || device->link.connected) { device->link.flags = NM_FLAGS_UNSET (device->link.flags, IFF_UP); @@ -397,8 +475,10 @@ link_set_arp (NMPlatform *platform, int ifindex) { NMFakePlatformLink *device = link_get (platform, ifindex); - if (!device) + if (!device) { + _LOGE ("failure changing link: netlink error (No such device)"); return FALSE; + } device->link.flags = NM_FLAGS_UNSET (device->link.flags, IFF_NOARP); @@ -412,8 +492,10 @@ link_set_noarp (NMPlatform *platform, int ifindex) { NMFakePlatformLink *device = link_get (platform, ifindex); - if (!device) + if (!device) { + _LOGE ("failure changing link: netlink error (No such device)"); return FALSE; + } device->link.flags = NM_FLAGS_SET (device->link.flags, IFF_NOARP); @@ -451,7 +533,8 @@ link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu) if (device) { device->link.mtu = mtu; link_changed (platform, device, TRUE); - } + } else + _LOGE ("failure changing link: netlink error (No such device)"); return !!device; } @@ -559,86 +642,69 @@ link_release (NMPlatform *platform, int master_idx, int slave_idx) } static gboolean -master_set_option (NMPlatform *platform, int master, const char *option, const char *value) +vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags, const NMPlatformLink **out_link) { - gs_free char *path = g_strdup_printf ("master:%d:%s", master, option); + NMFakePlatformLink *device; - return sysctl_set (platform, path, value); -} + if (!link_add (platform, name, NM_LINK_TYPE_VLAN, NULL, 0, out_link)) + return FALSE; -static char * -master_get_option (NMPlatform *platform, int master, const char *option) -{ - gs_free char *path = g_strdup_printf ("master:%d:%s", master, option); + device = link_get (platform, nm_platform_link_get_ifindex (platform, name)); - return sysctl_get (platform, path); -} + g_return_val_if_fail (device, FALSE); + g_return_val_if_fail (!device->lnk, FALSE); -static gboolean -slave_set_option (NMPlatform *platform, int slave, const char *option, const char *value) -{ - gs_free char *path = g_strdup_printf ("slave:%d:%s", slave, option); + device->lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL); + device->lnk->lnk_vlan.id = vlan_id; + device->link.parent = parent; - return sysctl_set (platform, path, value); + if (out_link) + *out_link = &device->link; + return TRUE; } -static char * -slave_get_option (NMPlatform *platform, int slave, const char *option) +static gboolean +link_vlan_change (NMPlatform *platform, + int ifindex, + NMVlanFlags flags_mask, + NMVlanFlags flags_set, + gboolean ingress_reset_all, + const NMVlanQosMapping *ingress_map, + gsize n_ingress_map, + gboolean egress_reset_all, + const NMVlanQosMapping *egress_map, + gsize n_egress_map) { - gs_free char *path = g_strdup_printf ("slave:%d:%s", slave, option); - - return sysctl_get (platform, path); + return FALSE; } static gboolean -vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags, NMPlatformLink *out_link) +link_vxlan_add (NMPlatform *platform, + const char *name, + const NMPlatformLnkVxlan *props, + const NMPlatformLink **out_link) { NMFakePlatformLink *device; - if (!link_add (platform, name, NM_LINK_TYPE_VLAN, NULL, 0, NULL)) + if (!link_add (platform, name, NM_LINK_TYPE_VXLAN, NULL, 0, out_link)) return FALSE; device = link_get (platform, nm_platform_link_get_ifindex (platform, name)); g_return_val_if_fail (device, FALSE); + g_return_val_if_fail (!device->lnk, FALSE); - device->vlan_id = vlan_id; - device->link.parent = parent; + device->lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VXLAN, NULL); + device->lnk->lnk_vxlan = *props; + device->link.parent = props->parent_ifindex; if (out_link) - *out_link = device->link; + *out_link = &device->link; 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, NMPlatformLink *out_link) +infiniband_partition_add (NMPlatform *platform, int parent, int p_key, const NMPlatformLink **out_link) { NMFakePlatformLink *device, *parent_device; gs_free char *name = NULL; @@ -652,62 +718,16 @@ infiniband_partition_add (NMPlatform *platform, int parent, int p_key, NMPlatfor device = link_get (platform, nm_platform_link_get_ifindex (platform, name)); g_return_val_if_fail (device, FALSE); + g_return_val_if_fail (!device->lnk, FALSE); - device->ib_p_key = p_key; + device->lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL); + device->lnk->lnk_infiniband.p_key = p_key; + device->lnk->lnk_infiniband.mode = "datagram"; device->link.parent = parent; return TRUE; } -static gboolean -infiniband_get_info (NMPlatform *platform, int ifindex, int *parent, int *p_key, const char **mode) -{ - NMFakePlatformLink *device; - - device = link_get (platform, ifindex); - g_return_val_if_fail (device, FALSE); - g_return_val_if_fail (device->link.type == NM_LINK_TYPE_INFINIBAND, FALSE); - - if (parent) - *parent = device->link.parent; - if (p_key) - *p_key = device->ib_p_key; - if (mode) - *mode = "datagram"; - - return TRUE; -} - -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) { @@ -861,9 +881,13 @@ ip6_address_get_all (NMPlatform *platform, int ifindex) } static gboolean -ip4_address_add (NMPlatform *platform, int ifindex, - in_addr_t addr, in_addr_t peer_addr, - int plen, guint32 lifetime, guint32 preferred, +ip4_address_add (NMPlatform *platform, + int ifindex, + in_addr_t addr, + int plen, + in_addr_t peer_addr, + guint32 lifetime, + guint32 preferred, const char *label) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); @@ -884,29 +908,36 @@ ip4_address_add (NMPlatform *platform, int ifindex, for (i = 0; i < priv->ip4_addresses->len; i++) { NMPlatformIP4Address *item = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i); + gboolean changed; - if (item->ifindex != address.ifindex) - continue; - if (item->address != address.address) - continue; - if (item->plen != address.plen) + if ( item->ifindex != address.ifindex + || item->address != address.address + || item->plen != address.plen + || !_ip4_address_equal_peer_net (item->peer_address, address.peer_address, address.plen)) continue; + changed = !nm_platform_ip4_address_cmp (item, &address); + memcpy (item, &address, sizeof (address)); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); + if (changed) + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED); return TRUE; } g_array_append_val (priv->ip4_addresses, address); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_ADDED); 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) +ip6_address_add (NMPlatform *platform, + int ifindex, + struct in6_addr addr, + int plen, + struct in6_addr peer_addr, + guint32 lifetime, + guint32 preferred, guint flags) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMPlatformIP6Address address; @@ -916,7 +947,7 @@ ip6_address_add (NMPlatform *platform, int ifindex, address.source = NM_IP_CONFIG_SOURCE_KERNEL; address.ifindex = ifindex; address.address = addr; - address.peer_address = peer_addr; + address.peer_address = (IN6_IS_ADDR_UNSPECIFIED (&peer_addr) || IN6_ARE_ADDR_EQUAL (&addr, &peer_addr)) ? in6addr_any : peer_addr; address.plen = plen; address.timestamp = nm_utils_get_monotonic_timestamp_s (); address.lifetime = lifetime; @@ -925,23 +956,22 @@ ip6_address_add (NMPlatform *platform, int ifindex, for (i = 0; i < priv->ip6_addresses->len; i++) { NMPlatformIP6Address *item = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i); + gboolean changed; - if (item->ifindex != address.ifindex) - continue; - if (!IN6_ARE_ADDR_EQUAL (&item->address, &address.address)) - continue; - if (item->plen != address.plen) + if ( item->ifindex != address.ifindex + || !IN6_ARE_ADDR_EQUAL (&item->address, &address.address)) continue; - if (nm_platform_ip6_address_cmp (item, &address) != 0) { - memcpy (item, &address, sizeof (address)); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); - } + changed = !nm_platform_ip6_address_cmp (item, &address); + + memcpy (item, &address, sizeof (address)); + if (changed) + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED); return TRUE; } g_array_append_val (priv->ip6_addresses, address); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_ADDED); return TRUE; } @@ -955,13 +985,15 @@ ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, 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 && - (!peer_address || address->peer_address == peer_address)) { + if ( address->ifindex == ifindex + && address->plen == plen + && address->address == addr + && ((peer_address ^ address->peer_address) & nm_utils_ip4_prefix_to_netmask (plen)) == 0) { 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, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex, &deleted_address, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_INTERNAL); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex, &deleted_address, NM_PLATFORM_SIGNAL_REMOVED); return TRUE; } } @@ -978,13 +1010,14 @@ ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int 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)) { + 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, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex, &deleted_address, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_INTERNAL); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex, &deleted_address, NM_PLATFORM_SIGNAL_REMOVED); return TRUE; } } @@ -993,7 +1026,7 @@ ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int } static const NMPlatformIP4Address * -ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen) +ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in_addr_t peer_address) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); int i; @@ -1001,7 +1034,10 @@ ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen) 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) + if ( address->ifindex == ifindex + && address->plen == plen + && address->address == addr + && _ip4_address_equal_peer_net (address->peer_address, peer_address, plen)) return address; } @@ -1105,7 +1141,7 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen memcpy (&deleted_route, route, sizeof (deleted_route)); g_array_remove_index (priv->ip4_routes, i); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &deleted_route, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_INTERNAL); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &deleted_route, NM_PLATFORM_SIGNAL_REMOVED); } return TRUE; @@ -1131,7 +1167,7 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, in memcpy (&deleted_route, route, sizeof (deleted_route)); g_array_remove_index (priv->ip6_routes, i); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &deleted_route, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_INTERNAL); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &deleted_route, NM_PLATFORM_SIGNAL_REMOVED); } return TRUE; @@ -1140,7 +1176,7 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, in static gboolean ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, in_addr_t network, int plen, in_addr_t gateway, - guint32 pref_src, guint32 metric, guint32 mss) + in_addr_t pref_src, guint32 metric, guint32 mss) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMPlatformIP4Route route; @@ -1194,12 +1230,12 @@ ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, } memcpy (item, &route, sizeof (route)); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &route, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &route, NM_PLATFORM_SIGNAL_CHANGED); return TRUE; } g_array_append_val (priv->ip4_routes, route); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &route, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &route, NM_PLATFORM_SIGNAL_ADDED); return TRUE; } @@ -1261,12 +1297,12 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, } memcpy (item, &route, sizeof (route)); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &route, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &route, NM_PLATFORM_SIGNAL_CHANGED); return TRUE; } g_array_append_val (priv->ip6_routes, route); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &route, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL); + g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &route, NM_PLATFORM_SIGNAL_ADDED); return TRUE; } @@ -1358,6 +1394,7 @@ nm_fake_platform_finalize (GObject *object) NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i); g_free (device->udi); + g_clear_pointer (&device->lnk, nmp_object_unref); } g_array_unref (priv->links); g_array_unref (priv->ip4_addresses); @@ -1390,6 +1427,8 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->link_delete = link_delete; platform_class->link_get_type_name = link_get_type_name; + platform_class->link_get_lnk = link_get_lnk; + platform_class->link_get_udi = link_get_udi; platform_class->link_set_up = link_set_up; @@ -1407,24 +1446,12 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->link_enslave = link_enslave; platform_class->link_release = link_release; - 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->link_vlan_change = link_vlan_change; + platform_class->link_vxlan_add = link_vxlan_add; platform_class->infiniband_partition_add = infiniband_partition_add; - platform_class->infiniband_get_info = infiniband_get_info; - - 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; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index ee6ba421..f73c228b 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -22,8 +22,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -40,24 +42,13 @@ #include #include -#if HAVE_LIBNL_INET6_ADDR_GEN_MODE || HAVE_LIBNL_INET6_TOKEN -#include -#if HAVE_LIBNL_INET6_ADDR_GEN_MODE && HAVE_KERNEL_INET6_ADDR_GEN_MODE -#include -#else -#define IN6_ADDR_GEN_MODE_EUI64 0 -#define IN6_ADDR_GEN_MODE_NONE 1 -#endif -#endif - -#include "gsystem-local-alloc.h" #include "nm-core-internal.h" #include "NetworkManagerUtils.h" #include "nm-linux-platform.h" #include "nm-platform-utils.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" -#include "nm-logging.h" +#include "nm-default.h" #include "wifi/wifi-utils.h" #include "wifi/wifi-utils-wext.h" #include "nmp-object.h" @@ -65,11 +56,67 @@ /* This is only included for the translation of VLAN flags */ #include "nm-setting-vlan.h" +#define VLAN_FLAG_MVRP 0x8 + +/*********************************************************************************************/ + +#define IFQDISCSIZ 32 + +/*********************************************************************************************/ + +#ifndef IFLA_PROMISCUITY +#define IFLA_PROMISCUITY 30 +#endif +#define IFLA_NUM_TX_QUEUES 31 +#define IFLA_NUM_RX_QUEUES 32 +#define IFLA_CARRIER 33 +#define IFLA_PHYS_PORT_ID 34 +#define IFLA_LINK_NETNSID 37 +#define __IFLA_MAX 39 + +#define IFLA_INET6_TOKEN 7 +#define IFLA_INET6_ADDR_GEN_MODE 8 +#define __IFLA_INET6_MAX 9 + +#define IFLA_VLAN_PROTOCOL 5 +#define __IFLA_VLAN_MAX 6 + +#define IFA_FLAGS 8 +#define __IFA_MAX 9 + +#define IFLA_MACVLAN_FLAGS 2 +#define __IFLA_MACVLAN_MAX 3 + +#define IFLA_IPTUN_LINK 1 +#define IFLA_IPTUN_LOCAL 2 +#define IFLA_IPTUN_REMOTE 3 +#define IFLA_IPTUN_TTL 4 +#define IFLA_IPTUN_TOS 5 +#define IFLA_IPTUN_ENCAP_LIMIT 6 +#define IFLA_IPTUN_FLOWINFO 7 +#define IFLA_IPTUN_FLAGS 8 +#define IFLA_IPTUN_PROTO 9 +#define IFLA_IPTUN_PMTUDISC 10 +#define __IFLA_IPTUN_MAX 19 +#ifndef IFLA_IPTUN_MAX +#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) +#endif + +#ifndef MACVLAN_FLAG_NOPROMISC +#define MACVLAN_FLAG_NOPROMISC 1 +#endif + +#define IP6_FLOWINFO_TCLASS_MASK 0x0FF00000 +#define IP6_FLOWINFO_TCLASS_SHIFT 20 +#define IP6_FLOWINFO_FLOWLABEL_MASK 0x000FFFFF + /*********************************************************************************************/ -#define _NMLOG_DOMAIN LOGD_PLATFORM #define _NMLOG_PREFIX_NAME "platform-linux" -#define _NMLOG(level, ...) _LOG(level, _NMLOG_DOMAIN, platform, __VA_ARGS__) +#define _NMLOG_DOMAIN LOGD_PLATFORM +#define _NMLOG2_DOMAIN LOGD_PLATFORM +#define _NMLOG(level, ...) _LOG(level, _NMLOG_DOMAIN, platform, __VA_ARGS__) +#define _NMLOG2(level, ...) _LOG(level, _NMLOG2_DOMAIN, NULL, __VA_ARGS__) #define _LOG(level, domain, self, ...) \ G_STMT_START { \ @@ -91,11 +138,7 @@ } \ } G_STMT_END -#define trace(...) _LOG (LOGL_TRACE, _NMLOG_DOMAIN, NULL, __VA_ARGS__) -#define debug(...) _LOG (LOGL_DEBUG, _NMLOG_DOMAIN, NULL, __VA_ARGS__) -#define info(...) _LOG (LOGL_INFO, _NMLOG_DOMAIN, NULL, __VA_ARGS__) -#define warning(...) _LOG (LOGL_WARN , _NMLOG_DOMAIN, NULL, __VA_ARGS__) -#define error(...) _LOG (LOGL_ERR , _NMLOG_DOMAIN, NULL, __VA_ARGS__) +#define LOG_FMT_IP_TUNNEL "adding %s '%s' parent %u local %s remote %s" /****************************************************************** * Forward declarations and enums @@ -111,6 +154,7 @@ typedef enum { DELAYED_ACTION_TYPE_REFRESH_LINK = (1LL << 5), DELAYED_ACTION_TYPE_MASTER_CONNECTED = (1LL << 6), DELAYED_ACTION_TYPE_READ_NETLINK = (1LL << 7), + DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE = (1LL << 8), __DELAYED_ACTION_TYPE_MAX, DELAYED_ACTION_TYPE_REFRESH_ALL = DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | @@ -122,1314 +166,2449 @@ typedef enum { DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX -1, } DelayedActionType; -static gboolean tun_get_properties_ifname (NMPlatform *platform, const char *ifname, NMPlatformTunProperties *props); +typedef enum { + /* Negative values are errors from kernel. Add dummy member to + * make enum signed. */ + _WAIT_FOR_NL_RESPONSE_RESULT_SYSTEM_ERROR = -1, + + WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN = 0, + WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK, + WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN, + WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC, + WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL, + WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT, + WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING, +} WaitForNlResponseResult; + +typedef void (*WaitForNlResponseCallback) (NMPlatform *platform, + guint32 seq_number, + WaitForNlResponseResult seq_result, + gpointer user_data); + static void delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gpointer user_data); static gboolean delayed_action_handle_all (NMPlatform *platform, gboolean read_netlink); -static void do_request_link (NMPlatform *platform, int ifindex, const char *name, gboolean handle_delayed_action); -static void do_request_all (NMPlatform *platform, DelayedActionType action_type, gboolean handle_delayed_action); +static void do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const char *name); +static void do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType action_type); static void cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data); -static gboolean event_handler_read_netlink_all (NMPlatform *platform, gboolean wait_for_acks); -static NMPCacheOpsType cache_remove_netlink (NMPlatform *platform, const NMPObject *obj_needle, NMPObject **out_obj_cache, gboolean *out_was_visible, NMPlatformReason reason); +static void cache_prune_candidates_prune (NMPlatform *platform); +static gboolean event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks); -/****************************************************************** - * libnl unility functions and wrappers - ******************************************************************/ +/*****************************************************************************/ -struct libnl_vtable +static const char * +wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, char *buf, gsize buf_size) { - void *handle; - void *handle_route; + char *buf0 = buf; - int (*f_nl_has_capability) (int capability); - int (*f_rtnl_link_get_link_netnsid) (const struct rtnl_link *link, gint32 *out_link_netnsid); -}; - -static int -_nl_f_nl_has_capability (int capability) -{ - return FALSE; + switch (seq_result) { + case WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN: + nm_utils_strbuf_append_str (&buf, &buf_size, "unknown"); + break; + case WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK: + nm_utils_strbuf_append_str (&buf, &buf_size, "success"); + break; + case WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN: + nm_utils_strbuf_append_str (&buf, &buf_size, "failure"); + break; + default: + if (seq_result < 0) + nm_utils_strbuf_append (&buf, &buf_size, "failure %d (%s)", -((int) seq_result), g_strerror (-((int) seq_result))); + else + nm_utils_strbuf_append (&buf, &buf_size, "internal failure %d", (int) seq_result); + break; + } + return buf0; } -static const struct libnl_vtable * -_nl_get_vtable (void) -{ - static struct libnl_vtable vtable; - - if (G_UNLIKELY (!vtable.f_nl_has_capability)) { - vtable.handle = dlopen ("libnl-3.so.200", RTLD_LAZY | RTLD_NOLOAD); - if (vtable.handle) { - vtable.f_nl_has_capability = dlsym (vtable.handle, "nl_has_capability"); - } - vtable.handle_route = dlopen ("libnl-route-3.so.200", RTLD_LAZY | RTLD_NOLOAD); - if (vtable.handle_route) { - vtable.f_rtnl_link_get_link_netnsid = dlsym (vtable.handle_route, "rtnl_link_get_link_netnsid"); - } - - if (!vtable.f_nl_has_capability) - vtable.f_nl_has_capability = &_nl_f_nl_has_capability; +/****************************************************************** + * Support IFLA_INET6_ADDR_GEN_MODE + ******************************************************************/ - trace ("libnl: rtnl_link_get_link_netnsid() %s", vtable.f_rtnl_link_get_link_netnsid ? "supported" : "not supported"); +static int _support_user_ipv6ll = 0; +#define _support_user_ipv6ll_still_undecided() (G_UNLIKELY (_support_user_ipv6ll == 0)) - g_return_val_if_fail (vtable.handle, &vtable); - g_return_val_if_fail (vtable.handle_route, &vtable); +static gboolean +_support_user_ipv6ll_get (void) +{ + if (_support_user_ipv6ll_still_undecided ()) { + _support_user_ipv6ll = -1; + _LOG2W ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "failed to detect; assume no support"); + return FALSE; } + return _support_user_ipv6ll > 0; - return &vtable; } -static gboolean -_nl_has_capability (int capability) +static void +_support_user_ipv6ll_detect (struct nlattr **tb) { - return (_nl_get_vtable ()->f_nl_has_capability) (capability); + if (_support_user_ipv6ll_still_undecided ()) { + if (tb[IFLA_INET6_ADDR_GEN_MODE]) { + _support_user_ipv6ll = 1; + _LOG2D ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "detected"); + } else { + _support_user_ipv6ll = -1; + _LOG2D ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "not detected"); + } + } } -static int -_rtnl_link_get_link_netnsid (const struct rtnl_link *link, gint32 *out_link_netnsid) -{ - const struct libnl_vtable *vtable; +/****************************************************************** + * Various utilities + ******************************************************************/ + +const NMIPAddr nm_ip_addr_zero = NMIPAddrInit; - g_return_val_if_fail (link, -NLE_INVAL); - g_return_val_if_fail (out_link_netnsid, -NLE_INVAL); +#define IPV4LL_NETWORK (htonl (0xA9FE0000L)) +#define IPV4LL_NETMASK (htonl (0xFFFF0000L)) - vtable = _nl_get_vtable (); - return vtable->f_rtnl_link_get_link_netnsid - ? vtable->f_rtnl_link_get_link_netnsid (link, out_link_netnsid) - : -NLE_OPNOTSUPP; +static gboolean +ip4_address_is_link_local (in_addr_t addr) +{ + return (addr & IPV4LL_NETMASK) == IPV4LL_NETWORK; } -gboolean -nm_platform_check_support_libnl_link_netnsid (void) +static guint +_nm_ip_config_source_to_rtprot (NMIPConfigSource source) { - return !!(_nl_get_vtable ()->f_rtnl_link_get_link_netnsid); + switch (source) { + case NM_IP_CONFIG_SOURCE_UNKNOWN: + return RTPROT_UNSPEC; + case NM_IP_CONFIG_SOURCE_KERNEL: + case NM_IP_CONFIG_SOURCE_RTPROT_KERNEL: + return RTPROT_KERNEL; + case NM_IP_CONFIG_SOURCE_DHCP: + return RTPROT_DHCP; + case NM_IP_CONFIG_SOURCE_RDISC: + return RTPROT_RA; + + default: + return RTPROT_STATIC; + } } -/* Automatic deallocation of local variables */ -#define auto_nl_object __attribute__((cleanup(_nl_auto_nl_object))) -static void -_nl_auto_nl_object (void *ptr) +static NMIPConfigSource +_nm_ip_config_source_from_rtprot (guint rtprot) { - struct nl_object **object = ptr; + switch (rtprot) { + case RTPROT_UNSPEC: + return NM_IP_CONFIG_SOURCE_UNKNOWN; + case RTPROT_KERNEL: + return NM_IP_CONFIG_SOURCE_RTPROT_KERNEL; + case RTPROT_REDIRECT: + return NM_IP_CONFIG_SOURCE_KERNEL; + case RTPROT_RA: + return NM_IP_CONFIG_SOURCE_RDISC; + case RTPROT_DHCP: + return NM_IP_CONFIG_SOURCE_DHCP; - if (object && *object) { - nl_object_put (*object); - *object = NULL; + default: + return NM_IP_CONFIG_SOURCE_USER; } } -#define auto_nl_addr __attribute__((cleanup(_nl_auto_nl_addr))) static void -_nl_auto_nl_addr (void *ptr) +clear_host_address (int family, const void *network, int plen, void *dst) { - struct nl_addr **object = ptr; + g_return_if_fail (plen == (guint8)plen); + g_return_if_fail (network); - if (object && *object) { - nl_addr_put (*object); - *object = NULL; + 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 (); } } -/* wrap the libnl alloc functions and abort on out-of-memory*/ - -static struct nl_addr * -_nl_addr_build (int family, const void *buf, size_t size) +static int +_vlan_qos_mapping_cmp_from (gconstpointer a, gconstpointer b, gpointer user_data) { - struct nl_addr *addr; + const NMVlanQosMapping *map_a = a; + const NMVlanQosMapping *map_b = b; - addr = nl_addr_build (family, (void *) buf, size); - if (!addr) - g_error ("nl_addr_build() failed with out of memory"); - - return addr; + if (map_a->from != map_b->from) + return map_a->from < map_b->from ? -1 : 1; + return 0; } -static struct rtnl_link * -_nl_rtnl_link_alloc (int ifindex, const char*name) +static int +_vlan_qos_mapping_cmp_from_ptr (gconstpointer a, gconstpointer b, gpointer user_data) { - struct rtnl_link *rtnllink; + return _vlan_qos_mapping_cmp_from (*((const NMVlanQosMapping **) a), + *((const NMVlanQosMapping **) b), + NULL); +} - rtnllink = rtnl_link_alloc (); - if (!rtnllink) - g_error ("rtnl_link_alloc() failed with out of memory"); +/****************************************************************** + * NMLinkType functions + ******************************************************************/ - if (ifindex > 0) - rtnl_link_set_ifindex (rtnllink, ifindex); - if (name) - rtnl_link_set_name (rtnllink, name); - return rtnllink; -} +typedef struct { + const NMLinkType nm_type; + const char *type_string; -static struct rtnl_addr * -_nl_rtnl_addr_alloc (int ifindex) -{ - struct rtnl_addr *rtnladdr; + /* IFLA_INFO_KIND / rtnl_link_get_type() where applicable; the rtnl type + * should only be specified if the device type can be created without + * additional parameters, and if the device type can be determined from + * the rtnl_type. eg, tun/tap should not be specified since both + * tun and tap devices use "tun", and InfiniBand should not be + * specified because a PKey is required at creation. Drivers set this + * value from their 'struct rtnl_link_ops' structure. + */ + const char *rtnl_type; - 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; -} + /* uevent DEVTYPE where applicable, from /sys/class/net//uevent; + * drivers set this value from their SET_NETDEV_DEV() call and the + * 'struct device_type' name member. + */ + const char *devtype; +} LinkDesc; -static struct rtnl_route * -_nl_rtnl_route_alloc (void) -{ - struct rtnl_route *rtnlroute = rtnl_route_alloc (); +static const LinkDesc linktypes[] = { + { NM_LINK_TYPE_NONE, "none", NULL, NULL }, + { NM_LINK_TYPE_UNKNOWN, "unknown", NULL, NULL }, - if (!rtnlroute) - g_error ("rtnl_route_alloc() failed with out of memory"); - return rtnlroute; -} + { NM_LINK_TYPE_ETHERNET, "ethernet", NULL, NULL }, + { NM_LINK_TYPE_INFINIBAND, "infiniband", NULL, NULL }, + { NM_LINK_TYPE_OLPC_MESH, "olpc-mesh", NULL, NULL }, + { NM_LINK_TYPE_WIFI, "wifi", NULL, "wlan" }, + { NM_LINK_TYPE_WWAN_ETHERNET, "wwan", NULL, "wwan" }, + { NM_LINK_TYPE_WIMAX, "wimax", "wimax", "wimax" }, -static struct rtnl_nexthop * -_nl_rtnl_route_nh_alloc (void) -{ - struct rtnl_nexthop *nexthop; + { NM_LINK_TYPE_DUMMY, "dummy", "dummy", NULL }, + { NM_LINK_TYPE_GRE, "gre", "gre", NULL }, + { NM_LINK_TYPE_GRETAP, "gretap", "gretap", NULL }, + { NM_LINK_TYPE_IFB, "ifb", "ifb", NULL }, + { NM_LINK_TYPE_IP6TNL, "ip6tnl", "ip6tnl", NULL }, + { NM_LINK_TYPE_IPIP, "ipip", "ipip", NULL }, + { NM_LINK_TYPE_LOOPBACK, "loopback", NULL, NULL }, + { NM_LINK_TYPE_MACVLAN, "macvlan", "macvlan", NULL }, + { NM_LINK_TYPE_MACVTAP, "macvtap", "macvtap", NULL }, + { NM_LINK_TYPE_OPENVSWITCH, "openvswitch", "openvswitch", NULL }, + { NM_LINK_TYPE_SIT, "sit", "sit", NULL }, + { NM_LINK_TYPE_TAP, "tap", NULL, NULL }, + { NM_LINK_TYPE_TUN, "tun", NULL, NULL }, + { NM_LINK_TYPE_VETH, "veth", "veth", NULL }, + { NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" }, + { NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" }, + { NM_LINK_TYPE_BNEP, "bluetooth", NULL, "bluetooth" }, - nexthop = rtnl_route_nh_alloc (); - if (!nexthop) - g_error ("rtnl_route_nh_alloc () failed with out of memory"); - return nexthop; -} + { NM_LINK_TYPE_BRIDGE, "bridge", "bridge", "bridge" }, + { NM_LINK_TYPE_BOND, "bond", "bond", "bond" }, + { NM_LINK_TYPE_TEAM, "team", "team", NULL }, +}; -/* rtnl_addr_set_prefixlen fails to update the nl_addr prefixlen */ -static void -_nl_rtnl_addr_set_prefixlen (struct rtnl_addr *rtnladdr, int plen) +static const char * +nm_link_type_to_rtnl_type_string (NMLinkType type) { - struct nl_addr *nladdr; - - rtnl_addr_set_prefixlen (rtnladdr, plen); + int i; - nladdr = rtnl_addr_get_local (rtnladdr); - if (nladdr) - nl_addr_set_prefixlen (nladdr, plen); + for (i = 0; i < G_N_ELEMENTS (linktypes); i++) { + if (type == linktypes[i].nm_type) + return linktypes[i].rtnl_type; + } + g_return_val_if_reached (NULL); } -static const char * -_nl_nlmsg_type_to_str (guint16 type, char *buf, gsize len) +const char * +nm_link_type_to_string (NMLinkType type) { - const char *str_type = NULL; + int i; - switch (type) { - case RTM_NEWLINK: str_type = "NEWLINK"; break; - case RTM_DELLINK: str_type = "DELLINK"; break; - case RTM_NEWADDR: str_type = "NEWADDR"; break; - case RTM_DELADDR: str_type = "DELADDR"; break; - case RTM_NEWROUTE: str_type = "NEWROUTE"; break; - case RTM_DELROUTE: str_type = "DELROUTE"; break; + for (i = 0; i < G_N_ELEMENTS (linktypes); i++) { + if (type == linktypes[i].nm_type) + return linktypes[i].type_string; } - if (str_type) - g_strlcpy (buf, str_type, len); - else - g_snprintf (buf, len, "(%d)", type); - return buf; + g_return_val_if_reached (NULL); } -/******************************************************************/ +/****************************************************************** + * Utilities + ******************************************************************/ -/* _nl_link_parse_info_data(): Re-fetches a link from the kernel - * and parses its IFLA_INFO_DATA using a caller-provided parser. +/* _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. * - * Code is stolen from rtnl_link_get_kernel(), nl_pickup(), and link_msg_parser(). - */ - -typedef int (*NMNLInfoDataParser) (struct nlattr *info_data, gpointer parser_data); + * 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; -typedef struct { - NMNLInfoDataParser parser; - gpointer parser_data; -} NMNLInfoDataClosure; + /* convert timestamp from 1/100th of a second to msec. */ + timestamp_nl_ms = ((gint64) timestamp_nl) * (1000 / 100); -static struct nla_policy info_data_link_policy[IFLA_MAX + 1] = { - [IFLA_LINKINFO] = { .type = NLA_NESTED }, -}; + /* 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; + } -static struct nla_policy info_data_link_info_policy[IFLA_INFO_MAX + 1] = { - [IFLA_INFO_DATA] = { .type = NLA_NESTED }, -}; + return timestamp_nl_ms; +} -static int -_nl_link_parse_info_data_cb (struct nl_msg *msg, void *arg) +static guint32 +_addrtime_timestamp_to_nm (guint32 timestamp, gint32 *out_now_nm) { - NMNLInfoDataClosure *closure = arg; - struct nlmsghdr *n = nlmsg_hdr (msg); - struct nlattr *tb[IFLA_MAX + 1]; - struct nlattr *li[IFLA_INFO_MAX + 1]; + struct timespec tp; + gint64 now_nl, now_nm, result; int err; - if (!nlmsg_valid_hdr (n, sizeof (struct ifinfomsg))) - return -NLE_MSG_TOOSHORT; + /* timestamp is unset. Default to 1. */ + if (!timestamp) { + if (out_now_nm) + *out_now_nm = 0; + return 1; + } - err = nlmsg_parse (n, sizeof (struct ifinfomsg), tb, IFLA_MAX, info_data_link_policy); - if (err < 0) - return err; + /* do all the calculations in milliseconds scale */ - if (!tb[IFLA_LINKINFO]) - return -NLE_MISSING_ATTR; + err = clock_gettime (CLOCK_MONOTONIC, &tp); + g_assert (err == 0); + 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)); - err = nla_parse_nested (li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], info_data_link_info_policy); - if (err < 0) - return err; + result = now_nm - (now_nl - _timestamp_nl_to_ms (timestamp, now_nl)); - if (!li[IFLA_INFO_DATA]) - return -NLE_MISSING_ATTR; + if (out_now_nm) + *out_now_nm = now_nm / 1000; + + /* converting the timestamp 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/timestamp 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 guint32 +_addrtime_extend_lifetime (guint32 lifetime, guint32 seconds) +{ + guint64 v; + + if ( lifetime == NM_PLATFORM_LIFETIME_PERMANENT + || seconds == 0) + return lifetime; + + v = (guint64) lifetime + (guint64) seconds; + return MIN (v, 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. + **/ +static void +_addrtime_get_lifetimes (guint32 timestamp, + guint32 lifetime, + guint32 preferred, + guint32 *out_timestamp, + guint32 *out_lifetime, + guint32 *out_preferred) +{ + gint32 now; + + if ( lifetime != NM_PLATFORM_LIFETIME_PERMANENT + || preferred != NM_PLATFORM_LIFETIME_PERMANENT) { + if (preferred > lifetime) + preferred = lifetime; + timestamp = _addrtime_timestamp_to_nm (timestamp, &now); + + if (now == 0) { + /* strange. failed to detect the last-update time and assumed that timestamp is 1. */ + nm_assert (timestamp == 1); + now = nm_utils_get_monotonic_timestamp_s (); + } + if (timestamp < now) { + guint32 diff = now - timestamp; + + lifetime = _addrtime_extend_lifetime (lifetime, diff); + preferred = _addrtime_extend_lifetime (preferred, diff); + } else + nm_assert (timestamp == now); + } else + timestamp = 0; + *out_timestamp = timestamp; + *out_lifetime = lifetime; + *out_preferred = preferred; +} + +/******************************************************************/ + +static const NMPObject * +_lookup_cached_link (const NMPCache *cache, int ifindex, gboolean *completed_from_cache, const NMPObject **link_cached) +{ + const NMPObject *obj; + + nm_assert (completed_from_cache && link_cached); + + if (!*completed_from_cache) { + obj = ifindex > 0 && cache ? nmp_cache_lookup_link (cache, ifindex) : NULL; + + if (obj && !obj->_link.netlink.is_in_netlink) + *link_cached = obj; + else + *link_cached = NULL; + *completed_from_cache = TRUE; + } + return *link_cached; +} + +/******************************************************************/ + +#define DEVTYPE_PREFIX "DEVTYPE=" + +static char * +_linktype_read_devtype (const char *sysfs_path) +{ + gs_free char *uevent = g_strdup_printf ("%s/uevent", sysfs_path); + char *contents = NULL; + char *cont, *end; + + if (!g_file_get_contents (uevent, &contents, NULL, NULL)) + return NULL; + for (cont = contents; cont; cont = end) { + end = strpbrk (cont, "\r\n"); + if (end) + *end++ = '\0'; + if (strncmp (cont, DEVTYPE_PREFIX, STRLEN (DEVTYPE_PREFIX)) == 0) { + cont += STRLEN (DEVTYPE_PREFIX); + memmove (contents, cont, strlen (cont) + 1); + return contents; + } + } + g_free (contents); + return NULL; +} + +static NMLinkType +_linktype_get_type (NMPlatform *platform, + const NMPCache *cache, + const char *kind, + int ifindex, + const char *ifname, + unsigned flags, + unsigned arptype, + gboolean *completed_from_cache, + const NMPObject **link_cached, + const char **out_kind) +{ + guint i; + + if (completed_from_cache) { + const NMPObject *obj; + + obj = _lookup_cached_link (cache, ifindex, completed_from_cache, link_cached); + + /* If we detected the link type before, we stick to that + * decision unless the "kind" changed. + * + * This way, we save edditional ethtool/sysctl lookups, but moreover, + * we keep the linktype stable and don't change it as long as the link + * exists. + * + * Note that kernel *can* reuse the ifindex (on integer overflow, and + * when moving interfce to other netns). Thus here there is a tiny potential + * of messing stuff up. */ + if ( obj + && !NM_IN_SET (obj->link.type, NM_LINK_TYPE_UNKNOWN, NM_LINK_TYPE_NONE) + && ( !kind + || !g_strcmp0 (kind, obj->link.kind))) { + nm_assert (obj->link.kind == g_intern_string (obj->link.kind)); + *out_kind = obj->link.kind; + return obj->link.type; + } + } + + *out_kind = g_intern_string (kind); + + if (kind) { + for (i = 0; i < G_N_ELEMENTS (linktypes); i++) { + if (g_strcmp0 (kind, linktypes[i].rtnl_type) == 0) + return linktypes[i].nm_type; + } + + if (!strcmp (kind, "tun")) { + NMPlatformTunProperties props; + + if ( platform + && nm_platform_link_tun_get_properties_ifname (platform, ifname, &props)) { + if (!g_strcmp0 (props.mode, "tap")) + return NM_LINK_TYPE_TAP; + if (!g_strcmp0 (props.mode, "tun")) + return NM_LINK_TYPE_TUN; + } + + /* try guessing the type using the link flags instead... */ + if (flags & IFF_POINTOPOINT) + return NM_LINK_TYPE_TUN; + return NM_LINK_TYPE_TAP; + } + } + + if (arptype == ARPHRD_LOOPBACK) + return NM_LINK_TYPE_LOOPBACK; + else if (arptype == ARPHRD_INFINIBAND) + return NM_LINK_TYPE_INFINIBAND; + else if (arptype == ARPHRD_SIT) + return NM_LINK_TYPE_SIT; + else if (arptype == ARPHRD_TUNNEL6) + return NM_LINK_TYPE_IP6TNL; + + if (ifname) { + gs_free char *driver = NULL; + gs_free char *sysfs_path = NULL; + gs_free char *anycast_mask = NULL; + gs_free char *devtype = NULL; + + /* Fallback OVS detection for kernel <= 3.16 */ + if (nmp_utils_ethtool_get_driver_info (ifname, &driver, NULL, NULL)) { + if (!g_strcmp0 (driver, "openvswitch")) + return NM_LINK_TYPE_OPENVSWITCH; + + if (arptype == 256) { + /* Some s390 CTC-type devices report 256 for the encapsulation type + * for some reason, but we need to call them Ethernet. + */ + if (!g_strcmp0 (driver, "ctcm")) + return NM_LINK_TYPE_ETHERNET; + } + } + + sysfs_path = g_strdup_printf ("/sys/class/net/%s", ifname); + anycast_mask = g_strdup_printf ("%s/anycast_mask", sysfs_path); + if (g_file_test (anycast_mask, G_FILE_TEST_EXISTS)) + return NM_LINK_TYPE_OLPC_MESH; + + devtype = _linktype_read_devtype (sysfs_path); + for (i = 0; devtype && i < G_N_ELEMENTS (linktypes); i++) { + if (g_strcmp0 (devtype, linktypes[i].devtype) == 0) { + if (linktypes[i].nm_type == NM_LINK_TYPE_BNEP) { + /* Both BNEP and 6lowpan use DEVTYPE=bluetooth, so we must + * use arptype to distinguish between them. + */ + if (arptype != ARPHRD_ETHER) + continue; + } + return linktypes[i].nm_type; + } + } + + /* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */ + if (wifi_utils_is_wifi (ifname, sysfs_path)) + return NM_LINK_TYPE_WIFI; + + /* Standard wired ethernet interfaces don't report an rtnl_link_type, so + * only allow fallback to Ethernet if no type is given. This should + * prevent future virtual network drivers from being treated as Ethernet + * when they should be Generic instead. + */ + if (arptype == ARPHRD_ETHER && !kind && !devtype) + return NM_LINK_TYPE_ETHERNET; + } + + return NM_LINK_TYPE_UNKNOWN; +} + +/****************************************************************** + * libnl unility functions and wrappers + ******************************************************************/ + +#define nm_auto_nlmsg __attribute__((cleanup(_nm_auto_nl_msg_cleanup))) +static void +_nm_auto_nl_msg_cleanup (void *ptr) +{ + nlmsg_free (*((struct nl_msg **) ptr)); +} + +static const char * +_nl_nlmsg_type_to_str (guint16 type, char *buf, gsize len) +{ + const char *str_type = NULL; + + switch (type) { + case RTM_NEWLINK: str_type = "NEWLINK"; break; + case RTM_DELLINK: str_type = "DELLINK"; break; + case RTM_NEWADDR: str_type = "NEWADDR"; break; + case RTM_DELADDR: str_type = "DELADDR"; break; + case RTM_NEWROUTE: str_type = "NEWROUTE"; break; + case RTM_DELROUTE: str_type = "DELROUTE"; break; + } + if (str_type) + g_strlcpy (buf, str_type, len); + else + g_snprintf (buf, len, "(%d)", type); + return buf; +} + +/****************************************************************** + * NMPObject/netlink functions + ******************************************************************/ + +#define _check_addr_or_errout(tb, attr, addr_len) \ + ({ \ + const struct nlattr *__t = (tb)[(attr)]; \ + \ + if (__t) { \ + if (nla_len (__t) != (addr_len)) { \ + goto errout; \ + } \ + } \ + !!__t; \ + }) + +/*****************************************************************************/ + +/* Copied and heavily modified from libnl3's inet6_parse_protinfo(). */ +static gboolean +_parse_af_inet6 (NMPlatform *platform, + struct nlattr *attr, + NMUtilsIPv6IfaceId *out_iid, + guint8 *out_iid_is_valid, + guint8 *out_addr_gen_mode_inv) +{ + static struct nla_policy policy[IFLA_INET6_MAX+1] = { + [IFLA_INET6_FLAGS] = { .type = NLA_U32 }, + [IFLA_INET6_CACHEINFO] = { .minlen = sizeof(struct ifla_cacheinfo) }, + [IFLA_INET6_CONF] = { .minlen = 4 }, + [IFLA_INET6_STATS] = { .minlen = 8 }, + [IFLA_INET6_ICMP6STATS] = { .minlen = 8 }, + [IFLA_INET6_TOKEN] = { .minlen = sizeof(struct in6_addr) }, + [IFLA_INET6_ADDR_GEN_MODE] = { .type = NLA_U8 }, + }; + struct nlattr *tb[IFLA_INET6_MAX+1]; + int err; + struct in6_addr i6_token; + gboolean iid_is_valid = FALSE; + guint8 i6_addr_gen_mode_inv = 0; + gboolean success = FALSE; + + err = nla_parse_nested (tb, IFLA_INET6_MAX, attr, policy); + if (err < 0) + goto errout; + + if (tb[IFLA_INET6_CONF] && nla_len(tb[IFLA_INET6_CONF]) % 4) + goto errout; + if (tb[IFLA_INET6_STATS] && nla_len(tb[IFLA_INET6_STATS]) % 8) + goto errout; + if (tb[IFLA_INET6_ICMP6STATS] && nla_len(tb[IFLA_INET6_ICMP6STATS]) % 8) + goto errout; + + if (_check_addr_or_errout (tb, IFLA_INET6_TOKEN, sizeof (struct in6_addr))) { + nla_memcpy (&i6_token, tb[IFLA_INET6_TOKEN], sizeof (struct in6_addr)); + if (!IN6_IS_ADDR_UNSPECIFIED (&i6_token)) + iid_is_valid = TRUE; + } + + /* Hack to detect support addrgenmode of the kernel. We only parse + * netlink messages that we receive from kernel, hence this check + * is valid. */ + _support_user_ipv6ll_detect (tb); + + if (tb[IFLA_INET6_ADDR_GEN_MODE]) { + i6_addr_gen_mode_inv = _nm_platform_uint8_inv (nla_get_u8 (tb[IFLA_INET6_ADDR_GEN_MODE])); + if (i6_addr_gen_mode_inv == 0) { + /* an inverse addrgenmode of zero is unexpected. We need to reserve zero + * to signal "unset". */ + goto errout; + } + } + + success = TRUE; + if (iid_is_valid) { + out_iid->id_u8[7] = i6_token.s6_addr[15]; + out_iid->id_u8[6] = i6_token.s6_addr[14]; + out_iid->id_u8[5] = i6_token.s6_addr[13]; + out_iid->id_u8[4] = i6_token.s6_addr[12]; + out_iid->id_u8[3] = i6_token.s6_addr[11]; + out_iid->id_u8[2] = i6_token.s6_addr[10]; + out_iid->id_u8[1] = i6_token.s6_addr[9]; + out_iid->id_u8[0] = i6_token.s6_addr[8]; + *out_iid_is_valid = TRUE; + } + *out_addr_gen_mode_inv = i6_addr_gen_mode_inv; +errout: + return success; +} + +/*****************************************************************************/ + +static NMPObject * +_parse_lnk_gre (const char *kind, struct nlattr *info_data) +{ + static struct nla_policy 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 }, + }; + struct nlattr *tb[IFLA_GRE_MAX + 1]; + int err; + NMPObject *obj; + NMPlatformLnkGre *props; + + if (!info_data || g_strcmp0 (kind, "gre")) + return NULL; + + err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, policy); + if (err < 0) + return NULL; + + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_GRE, NULL); + props = &obj->lnk_gre; + + props->parent_ifindex = tb[IFLA_GRE_LINK] ? nla_get_u32 (tb[IFLA_GRE_LINK]) : 0; + props->input_flags = tb[IFLA_GRE_IFLAGS] ? ntohs (nla_get_u16 (tb[IFLA_GRE_IFLAGS])) : 0; + props->output_flags = tb[IFLA_GRE_OFLAGS] ? ntohs (nla_get_u16 (tb[IFLA_GRE_OFLAGS])) : 0; + props->input_key = tb[IFLA_GRE_IKEY] ? ntohl (nla_get_u32 (tb[IFLA_GRE_IKEY])) : 0; + props->output_key = tb[IFLA_GRE_OKEY] ? ntohl (nla_get_u32 (tb[IFLA_GRE_OKEY])) : 0; + props->local = tb[IFLA_GRE_LOCAL] ? nla_get_u32 (tb[IFLA_GRE_LOCAL]) : 0; + props->remote = tb[IFLA_GRE_REMOTE] ? nla_get_u32 (tb[IFLA_GRE_REMOTE]) : 0; + props->tos = tb[IFLA_GRE_TOS] ? nla_get_u8 (tb[IFLA_GRE_TOS]) : 0; + props->ttl = tb[IFLA_GRE_TTL] ? nla_get_u8 (tb[IFLA_GRE_TTL]) : 0; + props->path_mtu_discovery = !tb[IFLA_GRE_PMTUDISC] || !!nla_get_u8 (tb[IFLA_GRE_PMTUDISC]); + + return obj; +} + +/*****************************************************************************/ + +/* IFLA_IPOIB_* were introduced in the 3.7 kernel, but the kernel headers + * we're building against might not have those properties even though the + * running kernel might. + */ +#define IFLA_IPOIB_UNSPEC 0 +#define IFLA_IPOIB_PKEY 1 +#define IFLA_IPOIB_MODE 2 +#define IFLA_IPOIB_UMCAST 3 +#undef IFLA_IPOIB_MAX +#define IFLA_IPOIB_MAX IFLA_IPOIB_UMCAST + +#define IPOIB_MODE_DATAGRAM 0 /* using unreliable datagram QPs */ +#define IPOIB_MODE_CONNECTED 1 /* using connected QPs */ + +static NMPObject * +_parse_lnk_infiniband (const char *kind, struct nlattr *info_data) +{ + static struct nla_policy policy[IFLA_IPOIB_MAX + 1] = { + [IFLA_IPOIB_PKEY] = { .type = NLA_U16 }, + [IFLA_IPOIB_MODE] = { .type = NLA_U16 }, + [IFLA_IPOIB_UMCAST] = { .type = NLA_U16 }, + }; + struct nlattr *tb[IFLA_IPOIB_MAX + 1]; + NMPlatformLnkInfiniband *info; + NMPObject *obj; + int err; + const char *mode; + + if (!info_data || g_strcmp0 (kind, "ipoib")) + return NULL; + + err = nla_parse_nested (tb, IFLA_IPOIB_MAX, info_data, policy); + if (err < 0) + return NULL; + + if (!tb[IFLA_IPOIB_PKEY] || !tb[IFLA_IPOIB_MODE]) + return NULL; + + switch (nla_get_u16 (tb[IFLA_IPOIB_MODE])) { + case IPOIB_MODE_DATAGRAM: + mode = "datagram"; + break; + case IPOIB_MODE_CONNECTED: + mode = "connected"; + break; + default: + return NULL; + } + + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_INFINIBAND, NULL); + info = &obj->lnk_infiniband; + + info->p_key = nla_get_u16 (tb[IFLA_IPOIB_PKEY]); + info->mode = mode; - return closure->parser (li[IFLA_INFO_DATA], closure->parser_data); + return obj; } -static int -_nl_link_parse_info_data (struct nl_sock *sk, int ifindex, - NMNLInfoDataParser parser, gpointer parser_data) +/*****************************************************************************/ + +static NMPObject * +_parse_lnk_ip6tnl (const char *kind, struct nlattr *info_data) { - NMNLInfoDataClosure data = { .parser = parser, .parser_data = parser_data }; - struct nl_msg *msg = NULL; - struct nl_cb *cb; - struct nl_cb *cb0; + static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, + [IFLA_IPTUN_LOCAL] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct in6_addr)}, + [IFLA_IPTUN_REMOTE] = { .type = NLA_UNSPEC, + .minlen = sizeof (struct in6_addr)}, + [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, + [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NLA_U8 }, + [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 }, + [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, + }; + struct nlattr *tb[IFLA_IPTUN_MAX + 1]; int err; + NMPObject *obj; + NMPlatformLnkIp6Tnl *props; + guint32 flowinfo; - err = rtnl_link_build_get_request (ifindex, NULL, &msg); + if (!info_data || g_strcmp0 (kind, "ip6tnl")) + return NULL; + + err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); if (err < 0) - return err; + return NULL; - err = nl_send_auto (sk, msg); - nlmsg_free (msg); + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IP6TNL, NULL); + props = &obj->lnk_ip6tnl; + + if (tb[IFLA_IPTUN_LINK]) + props->parent_ifindex = nla_get_u32 (tb[IFLA_IPTUN_LINK]); + if (tb[IFLA_IPTUN_LOCAL]) + memcpy (&props->local, nla_data (tb[IFLA_IPTUN_LOCAL]), sizeof (props->local)); + if (tb[IFLA_IPTUN_REMOTE]) + memcpy (&props->remote, nla_data (tb[IFLA_IPTUN_REMOTE]), sizeof (props->remote)); + if (tb[IFLA_IPTUN_TTL]) + props->ttl = nla_get_u8 (tb[IFLA_IPTUN_TTL]); + if (tb[IFLA_IPTUN_ENCAP_LIMIT]) + props->encap_limit = nla_get_u8 (tb[IFLA_IPTUN_ENCAP_LIMIT]); + if (tb[IFLA_IPTUN_FLOWINFO]) { + flowinfo = ntohl (nla_get_u32 (tb[IFLA_IPTUN_FLOWINFO])); + props->flow_label = flowinfo & IP6_FLOWINFO_FLOWLABEL_MASK; + props->tclass = (flowinfo & IP6_FLOWINFO_TCLASS_MASK) >> IP6_FLOWINFO_TCLASS_SHIFT; + } + if (tb[IFLA_IPTUN_PROTO]) + props->proto = nla_get_u8 (tb[IFLA_IPTUN_PROTO]); + + return obj; +} + +/*****************************************************************************/ + +static NMPObject * +_parse_lnk_ipip (const char *kind, struct nlattr *info_data) +{ + static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, + [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, + [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, + [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, + [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, + [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, + }; + struct nlattr *tb[IFLA_IPTUN_MAX + 1]; + int err; + NMPObject *obj; + NMPlatformLnkIpIp *props; + + if (!info_data || g_strcmp0 (kind, "ipip")) + return NULL; + + err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); if (err < 0) - return err; + return NULL; + + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_IPIP, NULL); + props = &obj->lnk_ipip; + + props->parent_ifindex = tb[IFLA_IPTUN_LINK] ? nla_get_u32 (tb[IFLA_IPTUN_LINK]) : 0; + props->local = tb[IFLA_IPTUN_LOCAL] ? nla_get_u32 (tb[IFLA_IPTUN_LOCAL]) : 0; + props->remote = tb[IFLA_IPTUN_REMOTE] ? nla_get_u32 (tb[IFLA_IPTUN_REMOTE]) : 0; + props->tos = tb[IFLA_IPTUN_TOS] ? nla_get_u8 (tb[IFLA_IPTUN_TOS]) : 0; + props->ttl = tb[IFLA_IPTUN_TTL] ? nla_get_u8 (tb[IFLA_IPTUN_TTL]) : 0; + props->path_mtu_discovery = !tb[IFLA_IPTUN_PMTUDISC] || !!nla_get_u8 (tb[IFLA_IPTUN_PMTUDISC]); + + return obj; +} + +/*****************************************************************************/ + +static NMPObject * +_parse_lnk_macvlan (const char *kind, struct nlattr *info_data) +{ + static struct nla_policy policy[IFLA_MACVLAN_MAX + 1] = { + [IFLA_MACVLAN_MODE] = { .type = NLA_U32 }, + [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 }, + }; + NMPlatformLnkMacvlan *props; + struct nlattr *tb[IFLA_MACVLAN_MAX + 1]; + int err; + NMPObject *obj; + gboolean tap; + + if (!info_data) + return NULL; - cb0 = nl_socket_get_cb (sk); - cb = nl_cb_clone (cb0); - nl_cb_put (cb0); - if (cb == NULL) - return -NLE_NOMEM; - nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, _nl_link_parse_info_data_cb, &data); + if (!g_strcmp0 (kind, "macvlan")) + tap = FALSE; + else if (!g_strcmp0 (kind, "macvtap")) + tap = TRUE; + else + return NULL; - err = nl_recvmsgs (sk, cb); - nl_cb_put (cb); + err = nla_parse_nested (tb, IFLA_MACVLAN_MAX, info_data, policy); if (err < 0) - return err; + return NULL; - nl_wait_for_ack (sk); - return 0; + if (!tb[IFLA_MACVLAN_MODE]) + return NULL; + + obj = nmp_object_new (tap ? NMP_OBJECT_TYPE_LNK_MACVTAP : NMP_OBJECT_TYPE_LNK_MACVLAN, NULL); + props = &obj->lnk_macvlan; + props->mode = nla_get_u32 (tb[IFLA_MACVLAN_MODE]); + props->tap = tap; + + if (tb[IFLA_MACVLAN_FLAGS]) + props->no_promisc = NM_FLAGS_HAS (nla_get_u16 (tb[IFLA_MACVLAN_FLAGS]), MACVLAN_FLAG_NOPROMISC); + + return obj; } -/******************************************************************/ +/*****************************************************************************/ -static int -_nl_sock_flush_data (struct nl_sock *sk) +static NMPObject * +_parse_lnk_sit (const char *kind, struct nlattr *info_data) { - int nle; - struct nl_cb *cb; - struct nl_cb *cb0; + static struct nla_policy policy[IFLA_IPTUN_MAX + 1] = { + [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, + [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, + [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, + [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, + [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, + [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, + [IFLA_IPTUN_FLAGS] = { .type = NLA_U16 }, + [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, + }; + struct nlattr *tb[IFLA_IPTUN_MAX + 1]; + int err; + NMPObject *obj; + NMPlatformLnkSit *props; - cb0 = nl_socket_get_cb (sk); - cb = nl_cb_clone (cb0); - nl_cb_put (cb0); - if (cb == NULL) - return -NLE_NOMEM; + if (!info_data || g_strcmp0 (kind, "sit")) + return NULL; - nl_cb_set (cb, NL_CB_VALID, NL_CB_DEFAULT, NULL, NULL); - nl_cb_set (cb, NL_CB_SEQ_CHECK, NL_CB_DEFAULT, NULL, NULL); - nl_cb_err (cb, NL_CB_DEFAULT, NULL, NULL); - do { - errno = 0; + err = nla_parse_nested (tb, IFLA_IPTUN_MAX, info_data, policy); + if (err < 0) + return NULL; - nle = nl_recvmsgs (sk, cb); + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_SIT, NULL); + props = &obj->lnk_sit; - /* Work around a libnl bug fixed in 3.2.22 (375a6294) */ - if (nle == 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) - nle = -NLE_AGAIN; - } while (nle != -NLE_AGAIN); + props->parent_ifindex = tb[IFLA_IPTUN_LINK] ? nla_get_u32 (tb[IFLA_IPTUN_LINK]) : 0; + props->local = tb[IFLA_IPTUN_LOCAL] ? nla_get_u32 (tb[IFLA_IPTUN_LOCAL]) : 0; + props->remote = tb[IFLA_IPTUN_REMOTE] ? nla_get_u32 (tb[IFLA_IPTUN_REMOTE]) : 0; + props->tos = tb[IFLA_IPTUN_TOS] ? nla_get_u8 (tb[IFLA_IPTUN_TOS]) : 0; + props->ttl = tb[IFLA_IPTUN_TTL] ? nla_get_u8 (tb[IFLA_IPTUN_TTL]) : 0; + props->path_mtu_discovery = !tb[IFLA_IPTUN_PMTUDISC] || !!nla_get_u8 (tb[IFLA_IPTUN_PMTUDISC]); + props->flags = tb[IFLA_IPTUN_FLAGS] ? nla_get_u16 (tb[IFLA_IPTUN_FLAGS]) : 0; + props->proto = tb[IFLA_IPTUN_PROTO] ? nla_get_u8 (tb[IFLA_IPTUN_PROTO]) : 0; - nl_cb_put (cb); - return nle; + return obj; } -static void -_nl_msg_set_seq (struct nl_sock *sk, struct nl_msg *msg, guint32 *out_seq) +/*****************************************************************************/ + +static gboolean +_vlan_qos_mapping_from_nla (struct nlattr *nlattr, + const NMVlanQosMapping **out_map, + guint *out_n_map) { - guint32 seq; + struct nlattr *nla; + int remaining; + gs_unref_ptrarray GPtrArray *array = NULL; + + G_STATIC_ASSERT (sizeof (NMVlanQosMapping) == sizeof (struct ifla_vlan_qos_mapping)); + G_STATIC_ASSERT (sizeof (((NMVlanQosMapping *) 0)->to) == sizeof (((struct ifla_vlan_qos_mapping *) 0)->to)); + G_STATIC_ASSERT (sizeof (((NMVlanQosMapping *) 0)->from) == sizeof (((struct ifla_vlan_qos_mapping *) 0)->from)); + G_STATIC_ASSERT (sizeof (NMVlanQosMapping) == sizeof (((NMVlanQosMapping *) 0)->from) + sizeof (((NMVlanQosMapping *) 0)->to)); + + nm_assert (out_map && !*out_map); + nm_assert (out_n_map && !*out_n_map); + + if (!nlattr) + return TRUE; + + array = g_ptr_array_new (); + nla_for_each_nested (nla, nlattr, remaining) { + if (nla_len (nla) < sizeof(NMVlanQosMapping)) + return FALSE; + g_ptr_array_add (array, nla_data (nla)); + } + + if (array->len > 0) { + NMVlanQosMapping *list; + guint i, j; + + /* The sorting is necessary, because for egress mapping, kernel + * doesn't sent the items strictly sorted by the from field. */ + g_ptr_array_sort_with_data (array, _vlan_qos_mapping_cmp_from_ptr, NULL); + + list = g_new (NMVlanQosMapping, array->len); + + for (i = 0, j = 0; i < array->len; i++) { + NMVlanQosMapping *map; - /* choose our own sequence number, because libnl does not ensure that - * it isn't zero -- which would confuse our checking for outstanding - * messages. */ - seq = nl_socket_use_seq (sk); - if (seq == 0) - seq = nl_socket_use_seq (sk); + map = array->pdata[i]; - nlmsg_hdr (msg)->nlmsg_seq = seq; - if (out_seq) - *out_seq = seq; + /* kernel doesn't really send us duplicates. Just be extra cautious + * because we want strong guarantees about the sort order and uniqueness + * of our mapping list (for simpler equality comparison). */ + if ( j > 0 + && list[j - 1].from == map->from) + list[j - 1] = *map; + else + list[j++] = *map; + } + + *out_n_map = j; + *out_map = list; + } + + return TRUE; } -static int -_nl_sock_request_link (NMPlatform *platform, struct nl_sock *sk, int ifindex, const char *name, guint32 *out_seq) +/* Copied and heavily modified from libnl3's vlan_parse() */ +static NMPObject * +_parse_lnk_vlan (const char *kind, struct nlattr *info_data) { - struct nl_msg *msg = NULL; + static struct nla_policy policy[IFLA_VLAN_MAX+1] = { + [IFLA_VLAN_ID] = { .type = NLA_U16 }, + [IFLA_VLAN_FLAGS] = { .minlen = sizeof(struct ifla_vlan_flags) }, + [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED }, + [IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED }, + [IFLA_VLAN_PROTOCOL] = { .type = NLA_U16 }, + }; + struct nlattr *tb[IFLA_VLAN_MAX+1]; int err; + nm_auto_nmpobj NMPObject *obj = NULL; + NMPObject *obj_result; - if (name && !name[0]) - name = NULL; + if (!info_data || g_strcmp0 (kind, "vlan")) + return NULL; - g_return_val_if_fail (ifindex > 0 || name, -NLE_INVAL); + if ((err = nla_parse_nested (tb, IFLA_VLAN_MAX, info_data, policy)) < 0) + return NULL; - _LOGt ("sock: request-link %d%s%s%s", ifindex, name ? ", \"" : "", name ? name : "", name ? "\"" : ""); + if (!tb[IFLA_VLAN_ID]) + return NULL; - if ((err = rtnl_link_build_get_request (ifindex, name, &msg)) < 0) - return err; + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL); + obj->lnk_vlan.id = nla_get_u16 (tb[IFLA_VLAN_ID]); - _nl_msg_set_seq (sk, msg, out_seq); + if (tb[IFLA_VLAN_FLAGS]) { + struct ifla_vlan_flags flags; - err = nl_send_auto (sk, msg); - nlmsg_free(msg); - if (err < 0) - return err; + nla_memcpy (&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags)); - return 0; + obj->lnk_vlan.flags = flags.flags; + } + + if (!_vlan_qos_mapping_from_nla (tb[IFLA_VLAN_INGRESS_QOS], + &obj->_lnk_vlan.ingress_qos_map, + &obj->_lnk_vlan.n_ingress_qos_map)) + return NULL; + + if (!_vlan_qos_mapping_from_nla (tb[IFLA_VLAN_EGRESS_QOS], + &obj->_lnk_vlan.egress_qos_map, + &obj->_lnk_vlan.n_egress_qos_map)) + return NULL; + + + obj_result = obj; + obj = NULL; + return obj_result; } -static int -_nl_sock_request_all (NMPlatform *platform, struct nl_sock *sk, NMPObjectType obj_type, guint32 *out_seq) -{ - const NMPClass *klass; - struct rtgenmsg gmsg = { 0 }; - struct nl_msg *msg; +/*****************************************************************************/ + +/* 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 + +/* older kernel header might not contain 'struct ifla_vxlan_port_range'. + * Redefine it. */ +struct nm_ifla_vxlan_port_range { + guint16 low; + guint16 high; +}; + +static NMPObject * +_parse_lnk_vxlan (const char *kind, struct nlattr *info_data) +{ + static struct nla_policy 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 nm_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 }, + }; + NMPlatformLnkVxlan *props; + struct nlattr *tb[IFLA_VXLAN_MAX + 1]; + struct nm_ifla_vxlan_port_range *range; int err; + NMPObject *obj; - klass = nmp_class_from_type (obj_type); + if (!info_data || g_strcmp0 (kind, "vxlan")) + return NULL; - _LOGt ("sock: request-all-%s", klass->obj_type_name); + err = nla_parse_nested (tb, IFLA_VXLAN_MAX, info_data, policy); + if (err < 0) + return NULL; - /* reimplement - * nl_rtgen_request (sk, klass->rtm_gettype, klass->addr_family, NLM_F_DUMP); - * because we need the sequence number. - */ - msg = nlmsg_alloc_simple (klass->rtm_gettype, NLM_F_DUMP); - if (!msg) - return -NLE_NOMEM; + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_VXLAN, NULL); + + props = &obj->lnk_vxlan; + + if (tb[IFLA_VXLAN_LINK]) + props->parent_ifindex = nla_get_u32 (tb[IFLA_VXLAN_LINK]); + if (tb[IFLA_VXLAN_ID]) + 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)); + + if (tb[IFLA_VXLAN_AGEING]) + props->ageing = nla_get_u32 (tb[IFLA_VXLAN_AGEING]); + if (tb[IFLA_VXLAN_LIMIT]) + props->limit = nla_get_u32 (tb[IFLA_VXLAN_LIMIT]); + if (tb[IFLA_VXLAN_TOS]) + props->tos = nla_get_u8 (tb[IFLA_VXLAN_TOS]); + if (tb[IFLA_VXLAN_TTL]) + props->ttl = nla_get_u8 (tb[IFLA_VXLAN_TTL]); + + if (tb[IFLA_VXLAN_PORT]) + props->dst_port = ntohs (nla_get_u16 (tb[IFLA_VXLAN_PORT])); + + if (tb[IFLA_VXLAN_PORT_RANGE]) { + range = nla_data (tb[IFLA_VXLAN_PORT_RANGE]); + props->src_port_min = ntohs (range->low); + props->src_port_max = ntohs (range->high); + } + + if (tb[IFLA_VXLAN_LEARNING]) + props->learning = !!nla_get_u8 (tb[IFLA_VXLAN_LEARNING]); + if (tb[IFLA_VXLAN_PROXY]) + props->proxy = !!nla_get_u8 (tb[IFLA_VXLAN_PROXY]); + if (tb[IFLA_VXLAN_RSC]) + props->rsc = !!nla_get_u8 (tb[IFLA_VXLAN_RSC]); + if (tb[IFLA_VXLAN_L2MISS]) + props->l2miss = !!nla_get_u8 (tb[IFLA_VXLAN_L2MISS]); + if (tb[IFLA_VXLAN_L3MISS]) + props->l3miss = !!nla_get_u8 (tb[IFLA_VXLAN_L3MISS]); + + return obj; +} + +/*****************************************************************************/ + +/* Copied and heavily modified from libnl3's link_msg_parser(). */ +static NMPObject * +_new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr *nlh, gboolean id_only) +{ + static struct nla_policy policy[IFLA_MAX+1] = { + [IFLA_IFNAME] = { .type = NLA_STRING, + .maxlen = IFNAMSIZ }, + [IFLA_MTU] = { .type = NLA_U32 }, + [IFLA_TXQLEN] = { .type = NLA_U32 }, + [IFLA_LINK] = { .type = NLA_U32 }, + [IFLA_WEIGHT] = { .type = NLA_U32 }, + [IFLA_MASTER] = { .type = NLA_U32 }, + [IFLA_OPERSTATE] = { .type = NLA_U8 }, + [IFLA_LINKMODE] = { .type = NLA_U8 }, + [IFLA_LINKINFO] = { .type = NLA_NESTED }, + [IFLA_QDISC] = { .type = NLA_STRING, + .maxlen = IFQDISCSIZ }, + [IFLA_STATS] = { .minlen = sizeof(struct rtnl_link_stats) }, + [IFLA_STATS64] = { .minlen = sizeof(struct rtnl_link_stats64)}, + [IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) }, + [IFLA_IFALIAS] = { .type = NLA_STRING, .maxlen = IFALIASZ }, + [IFLA_NUM_VF] = { .type = NLA_U32 }, + [IFLA_AF_SPEC] = { .type = NLA_NESTED }, + [IFLA_PROMISCUITY] = { .type = NLA_U32 }, + [IFLA_NUM_TX_QUEUES] = { .type = NLA_U32 }, + [IFLA_NUM_RX_QUEUES] = { .type = NLA_U32 }, + [IFLA_GROUP] = { .type = NLA_U32 }, + [IFLA_CARRIER] = { .type = NLA_U8 }, + [IFLA_PHYS_PORT_ID] = { .type = NLA_UNSPEC }, + [IFLA_NET_NS_PID] = { .type = NLA_U32 }, + [IFLA_NET_NS_FD] = { .type = NLA_U32 }, + }; + static struct nla_policy policy_link_info[IFLA_INFO_MAX+1] = { + [IFLA_INFO_KIND] = { .type = NLA_STRING }, + [IFLA_INFO_DATA] = { .type = NLA_NESTED }, + [IFLA_INFO_XSTATS] = { .type = NLA_NESTED }, + }; + const struct ifinfomsg *ifi; + struct nlattr *tb[IFLA_MAX+1]; + struct nlattr *li[IFLA_INFO_MAX+1]; + struct nlattr *nl_info_data = NULL; + const char *nl_info_kind = NULL; + int err; + nm_auto_nmpobj NMPObject *obj = NULL; + NMPObject *obj_result = NULL; + gboolean completed_from_cache_val = FALSE; + gboolean *completed_from_cache = cache ? &completed_from_cache_val : NULL; + const NMPObject *link_cached = NULL; + NMPObject *lnk_data = NULL; + + if (!nlmsg_valid_hdr (nlh, sizeof (*ifi))) + return NULL; + ifi = nlmsg_data(nlh); + + obj = nmp_object_new_link (ifi->ifi_index); + + if (id_only) + goto id_only_handled; - gmsg.rtgen_family = klass->addr_family; - err = nlmsg_append (msg, &gmsg, sizeof (gmsg), NLMSG_ALIGNTO); + err = nlmsg_parse (nlh, sizeof (*ifi), tb, IFLA_MAX, policy); if (err < 0) goto errout; - _nl_msg_set_seq (sk, msg, out_seq); + if (!tb[IFLA_IFNAME]) + goto errout; + nla_strlcpy(obj->link.name, tb[IFLA_IFNAME], IFNAMSIZ); + if (!obj->link.name[0]) + goto errout; - err = nl_send_auto (sk, msg); -errout: - nlmsg_free(msg); + if (tb[IFLA_LINKINFO]) { + err = nla_parse_nested (li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], policy_link_info); + if (err < 0) + goto errout; - return err >= 0 ? 0 : err; -} + if (li[IFLA_INFO_KIND]) + nl_info_kind = nla_get_string (li[IFLA_INFO_KIND]); -/******************************************************************/ + nl_info_data = li[IFLA_INFO_DATA]; + } -#if HAVE_LIBNL_INET6_ADDR_GEN_MODE -static int _support_user_ipv6ll = 0; -#define _support_user_ipv6ll_still_undecided() (G_UNLIKELY (_support_user_ipv6ll == 0)) -#else -#define _support_user_ipv6ll_still_undecided() (FALSE) -#endif + obj->link.flags = ifi->ifi_flags; + obj->link.connected = NM_FLAGS_HAS (obj->link.flags, IFF_LOWER_UP); + obj->link.arptype = ifi->ifi_type; + + obj->link.type = _linktype_get_type (platform, + cache, + nl_info_kind, + obj->link.ifindex, + obj->link.name, + obj->link.flags, + obj->link.arptype, + completed_from_cache, + &link_cached, + &obj->link.kind); + + if (tb[IFLA_MASTER]) + obj->link.master = nla_get_u32 (tb[IFLA_MASTER]); + + if (tb[IFLA_LINK]) { + if (!tb[IFLA_LINK_NETNSID]) + obj->link.parent = nla_get_u32 (tb[IFLA_LINK]); + else + obj->link.parent = NM_PLATFORM_LINK_OTHER_NETNS; + } -static gboolean -_support_user_ipv6ll_get (void) -{ -#if HAVE_LIBNL_INET6_ADDR_GEN_MODE - if (_support_user_ipv6ll_still_undecided ()) { - _support_user_ipv6ll = -1; - nm_log_warn (LOGD_PLATFORM, "kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "failed to detect; assume no support"); - } else - return _support_user_ipv6ll > 0; -#endif + if (tb[IFLA_ADDRESS]) { + int l = nla_len (tb[IFLA_ADDRESS]); - return FALSE; -} + if (l > 0 && l <= NM_UTILS_HWADDR_LEN_MAX) { + G_STATIC_ASSERT (NM_UTILS_HWADDR_LEN_MAX == sizeof (obj->link.addr.data)); + memcpy (obj->link.addr.data, nla_data (tb[IFLA_ADDRESS]), l); + obj->link.addr.len = l; + } + } -static void -_support_user_ipv6ll_detect (const struct rtnl_link *rtnl_link) -{ -#if HAVE_LIBNL_INET6_ADDR_GEN_MODE - /* If we ever see a link with valid IPv6 link-local address - * generation modes, the kernel supports it. - */ - if (_support_user_ipv6ll_still_undecided ()) { - uint8_t mode; + if (tb[IFLA_AF_SPEC]) { + struct nlattr *af_attr; + int remaining; + + nla_for_each_nested (af_attr, tb[IFLA_AF_SPEC], remaining) { + switch (nla_type (af_attr)) { + case AF_INET6: + _parse_af_inet6 (platform, + af_attr, + &obj->link.inet6_token.iid, + &obj->link.inet6_token.is_valid, + &obj->link.inet6_addr_gen_mode_inv); + break; + } + } + } - if (rtnl_link_inet6_get_addr_gen_mode ((struct rtnl_link *) rtnl_link, &mode) == 0) { - _support_user_ipv6ll = 1; - nm_log_dbg (LOGD_PLATFORM, "kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "detected"); - } else { - _support_user_ipv6ll = -1; - nm_log_dbg (LOGD_PLATFORM, "kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "not detected"); + if (tb[IFLA_MTU]) + obj->link.mtu = nla_get_u32 (tb[IFLA_MTU]); + + switch (obj->link.type) { + case NM_LINK_TYPE_GRE: + lnk_data = _parse_lnk_gre (nl_info_kind, nl_info_data); + break; + case NM_LINK_TYPE_INFINIBAND: + lnk_data = _parse_lnk_infiniband (nl_info_kind, nl_info_data); + break; + case NM_LINK_TYPE_IP6TNL: + lnk_data = _parse_lnk_ip6tnl (nl_info_kind, nl_info_data); + break; + case NM_LINK_TYPE_IPIP: + lnk_data = _parse_lnk_ipip (nl_info_kind, nl_info_data); + break; + case NM_LINK_TYPE_MACVLAN: + case NM_LINK_TYPE_MACVTAP: + lnk_data = _parse_lnk_macvlan (nl_info_kind, nl_info_data); + break; + case NM_LINK_TYPE_SIT: + lnk_data = _parse_lnk_sit (nl_info_kind, nl_info_data); + break; + case NM_LINK_TYPE_VLAN: + lnk_data = _parse_lnk_vlan (nl_info_kind, nl_info_data); + break; + case NM_LINK_TYPE_VXLAN: + lnk_data = _parse_lnk_vxlan (nl_info_kind, nl_info_data); + break; + default: + goto lnk_data_handled; + } + + /* We always try to look into the cache and reuse the object there. + * We do that, because we consider the lnk object as immutable and don't + * modify it after creating. Hence we can share it and reuse. + * + * Also, sometimes the info-data is missing for updates. In this case + * we want to keep the previously received lnk_data. */ + if (completed_from_cache) { + _lookup_cached_link (cache, obj->link.ifindex, completed_from_cache, &link_cached); + if ( link_cached + && link_cached->link.type == obj->link.type + && ( !lnk_data + || nmp_object_equal (lnk_data, link_cached->_link.netlink.lnk))) { + nmp_object_unref (lnk_data); + lnk_data = nmp_object_ref (link_cached->_link.netlink.lnk); } } -#endif + +lnk_data_handled: + obj->_link.netlink.lnk = lnk_data; + + obj->_link.netlink.is_in_netlink = TRUE; +id_only_handled: + obj_result = obj; + obj = NULL; +errout: + return obj_result; } -/******************************************************************/ +/* Copied and heavily modified from libnl3's addr_msg_parser(). */ +static NMPObject * +_new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only) +{ + static struct nla_policy policy[IFA_MAX+1] = { + [IFA_LABEL] = { .type = NLA_STRING, + .maxlen = IFNAMSIZ }, + [IFA_CACHEINFO] = { .minlen = sizeof(struct ifa_cacheinfo) }, + }; + const struct ifaddrmsg *ifa; + struct nlattr *tb[IFA_MAX+1]; + int err; + gboolean is_v4; + nm_auto_nmpobj NMPObject *obj = NULL; + NMPObject *obj_result = NULL; + int addr_len; + guint32 lifetime, preferred, timestamp; + + if (!nlmsg_valid_hdr (nlh, sizeof (*ifa))) + return NULL; + ifa = nlmsg_data(nlh); + + if (!NM_IN_SET (ifa->ifa_family, AF_INET, AF_INET6)) + goto errout; + is_v4 = ifa->ifa_family == AF_INET; + + err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, policy); + if (err < 0) + goto errout; + + addr_len = is_v4 + ? sizeof (in_addr_t) + : sizeof (struct in6_addr); + + /*****************************************************************/ + + obj = nmp_object_new (is_v4 ? NMP_OBJECT_TYPE_IP4_ADDRESS : NMP_OBJECT_TYPE_IP6_ADDRESS, NULL); + + obj->ip_address.ifindex = ifa->ifa_index; + obj->ip_address.plen = ifa->ifa_prefixlen; + + _check_addr_or_errout (tb, IFA_ADDRESS, addr_len); + _check_addr_or_errout (tb, IFA_LOCAL, addr_len); + if (is_v4) { + /* For IPv4, kernel omits IFA_LOCAL/IFA_ADDRESS if (and only if) they + * are effectively 0.0.0.0 (all-zero). */ + if (tb[IFA_LOCAL]) + memcpy (&obj->ip4_address.address, nla_data (tb[IFA_LOCAL]), addr_len); + if (tb[IFA_ADDRESS]) + memcpy (&obj->ip4_address.peer_address, nla_data (tb[IFA_ADDRESS]), addr_len); + } else { + /* For IPv6, IFA_ADDRESS is always present. + * + * If IFA_LOCAL is missing, IFA_ADDRESS is @address and @peer_address + * is :: (all-zero). + * + * If unexpectely IFA_ADDRESS is missing, make the best of it -- but it _should_ + * actually be there. */ + if (tb[IFA_ADDRESS] || tb[IFA_LOCAL]) { + if (tb[IFA_LOCAL]) { + memcpy (&obj->ip6_address.address, nla_data (tb[IFA_LOCAL]), addr_len); + if (tb[IFA_ADDRESS]) + memcpy (&obj->ip6_address.peer_address, nla_data (tb[IFA_ADDRESS]), addr_len); + else + obj->ip6_address.peer_address = obj->ip6_address.address; + } else + memcpy (&obj->ip6_address.address, nla_data (tb[IFA_ADDRESS]), addr_len); + } + } -static int _support_kernel_extended_ifa_flags = 0; + obj->ip_address.source = NM_IP_CONFIG_SOURCE_KERNEL; -#define _support_kernel_extended_ifa_flags_still_undecided() (G_UNLIKELY (_support_kernel_extended_ifa_flags == 0)) + if (!is_v4) { + obj->ip6_address.flags = tb[IFA_FLAGS] + ? nla_get_u32 (tb[IFA_FLAGS]) + : ifa->ifa_flags; + } -static void -_support_kernel_extended_ifa_flags_detect (struct nl_msg *msg) -{ - struct nlmsghdr *msg_hdr; + if (is_v4) { + if (tb[IFA_LABEL]) { + char label[IFNAMSIZ]; - if (!_support_kernel_extended_ifa_flags_still_undecided ()) - return; + nla_strlcpy (label, tb[IFA_LABEL], IFNAMSIZ); - msg_hdr = nlmsg_hdr (msg); - if (msg_hdr->nlmsg_type != RTM_NEWADDR) - return; + /* Check for ':'; we're only interested in labels used as interface aliases */ + if (strchr (label, ':')) + g_strlcpy (obj->ip4_address.label, label, sizeof (obj->ip4_address.label)); + } + } - /* the extended address flags are only set for AF_INET6 */ - if (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family != AF_INET6) - return; + lifetime = NM_PLATFORM_LIFETIME_PERMANENT; + preferred = NM_PLATFORM_LIFETIME_PERMANENT; + timestamp = 0; + /* IPv6 only */ + if (tb[IFA_CACHEINFO]) { + const struct ifa_cacheinfo *ca = nla_data(tb[IFA_CACHEINFO]); - /* 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). - **/ - _support_kernel_extended_ifa_flags = - nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), 8 /* IFA_FLAGS */) - ? 1 : -1; + lifetime = ca->ifa_valid; + preferred = ca->ifa_prefered; + timestamp = ca->tstamp; + } + _addrtime_get_lifetimes (timestamp, + lifetime, + preferred, + &obj->ip_address.timestamp, + &obj->ip_address.lifetime, + &obj->ip_address.preferred); + + obj_result = obj; + obj = NULL; +errout: + return obj_result; } -static gboolean -_support_kernel_extended_ifa_flags_get (void) +/* Copied and heavily modified from libnl3's rtnl_route_parse() and parse_multipath(). */ +static NMPObject * +_new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only) { - if (_support_kernel_extended_ifa_flags_still_undecided ()) { - nm_log_warn (LOGD_PLATFORM, "Unable to detect kernel support for extended IFA_FLAGS. Assume no kernel support."); - _support_kernel_extended_ifa_flags = -1; - } - return _support_kernel_extended_ifa_flags > 0; -} + static struct nla_policy policy[RTA_MAX+1] = { + [RTA_IIF] = { .type = NLA_U32 }, + [RTA_OIF] = { .type = NLA_U32 }, + [RTA_PRIORITY] = { .type = NLA_U32 }, + [RTA_FLOW] = { .type = NLA_U32 }, + [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) }, + [RTA_METRICS] = { .type = NLA_NESTED }, + [RTA_MULTIPATH] = { .type = NLA_NESTED }, + }; + const struct rtmsg *rtm; + struct nlattr *tb[RTA_MAX + 1]; + int err; + gboolean is_v4; + nm_auto_nmpobj NMPObject *obj = NULL; + NMPObject *obj_result = NULL; + int addr_len; + struct { + gboolean is_present; + int ifindex; + NMIPAddr gateway; + } nh; + guint32 mss; + guint32 table; + + if (!nlmsg_valid_hdr (nlh, sizeof (*rtm))) + return NULL; + rtm = nlmsg_data(nlh); -/****************************************************************** - * Object type specific utilities - ******************************************************************/ + /***************************************************************** + * only handle ~normal~ routes. + *****************************************************************/ -static guint -_nm_ip_config_source_to_rtprot (NMIPConfigSource source) -{ - switch (source) { - case NM_IP_CONFIG_SOURCE_UNKNOWN: - return RTPROT_UNSPEC; - case NM_IP_CONFIG_SOURCE_KERNEL: - case NM_IP_CONFIG_SOURCE_RTPROT_KERNEL: - return RTPROT_KERNEL; - case NM_IP_CONFIG_SOURCE_DHCP: - return RTPROT_DHCP; - case NM_IP_CONFIG_SOURCE_RDISC: - return RTPROT_RA; + if (!NM_IN_SET (rtm->rtm_family, AF_INET, AF_INET6)) + goto errout; - default: - return RTPROT_STATIC; - } -} + if ( rtm->rtm_type != RTN_UNICAST + || rtm->rtm_tos != 0) + goto errout; -static NMIPConfigSource -_nm_ip_config_source_from_rtprot (guint rtprot) -{ - switch (rtprot) { - case RTPROT_UNSPEC: - return NM_IP_CONFIG_SOURCE_UNKNOWN; - case RTPROT_KERNEL: - return NM_IP_CONFIG_SOURCE_RTPROT_KERNEL; - case RTPROT_REDIRECT: - return NM_IP_CONFIG_SOURCE_KERNEL; - case RTPROT_RA: - return NM_IP_CONFIG_SOURCE_RDISC; - case RTPROT_DHCP: - return NM_IP_CONFIG_SOURCE_DHCP; + err = nlmsg_parse (nlh, sizeof (struct rtmsg), tb, RTA_MAX, policy); + if (err < 0) + goto errout; - default: - return NM_IP_CONFIG_SOURCE_USER; - } -} + table = tb[RTA_TABLE] + ? nla_get_u32 (tb[RTA_TABLE]) + : (guint32) rtm->rtm_table; + if (table != RT_TABLE_MAIN) + goto errout; -/******************************************************************/ + /*****************************************************************/ -typedef struct { - const NMLinkType nm_type; - const char *type_string; + is_v4 = rtm->rtm_family == AF_INET; + addr_len = is_v4 + ? sizeof (in_addr_t) + : sizeof (struct in6_addr); - /* IFLA_INFO_KIND / rtnl_link_get_type() where applicable; the rtnl type - * should only be specified if the device type can be created without - * additional parameters, and if the device type can be determined from - * the rtnl_type. eg, tun/tap should not be specified since both - * tun and tap devices use "tun", and InfiniBand should not be - * specified because a PKey is required at creation. Drivers set this - * value from their 'struct rtnl_link_ops' structure. - */ - const char *rtnl_type; + /***************************************************************** + * parse nexthops. Only handle routes with one nh. + *****************************************************************/ - /* uevent DEVTYPE where applicable, from /sys/class/net//uevent; - * drivers set this value from their SET_NETDEV_DEV() call and the - * 'struct device_type' name member. - */ - const char *devtype; -} LinkDesc; + memset (&nh, 0, sizeof (nh)); -static const LinkDesc linktypes[] = { - { NM_LINK_TYPE_NONE, "none", NULL, NULL }, - { NM_LINK_TYPE_UNKNOWN, "unknown", NULL, NULL }, + if (tb[RTA_MULTIPATH]) { + struct rtnexthop *rtnh = nla_data (tb[RTA_MULTIPATH]); + size_t tlen = nla_len(tb[RTA_MULTIPATH]); - { NM_LINK_TYPE_ETHERNET, "ethernet", NULL, NULL }, - { NM_LINK_TYPE_INFINIBAND, "infiniband", NULL, NULL }, - { NM_LINK_TYPE_OLPC_MESH, "olpc-mesh", NULL, NULL }, - { NM_LINK_TYPE_WIFI, "wifi", NULL, "wlan" }, - { NM_LINK_TYPE_WWAN_ETHERNET, "wwan", NULL, "wwan" }, - { NM_LINK_TYPE_WIMAX, "wimax", "wimax", "wimax" }, + while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) { - { NM_LINK_TYPE_DUMMY, "dummy", "dummy", NULL }, - { NM_LINK_TYPE_GRE, "gre", "gre", NULL }, - { NM_LINK_TYPE_GRETAP, "gretap", "gretap", NULL }, - { NM_LINK_TYPE_IFB, "ifb", "ifb", NULL }, - { NM_LINK_TYPE_LOOPBACK, "loopback", NULL, NULL }, - { NM_LINK_TYPE_MACVLAN, "macvlan", "macvlan", NULL }, - { NM_LINK_TYPE_MACVTAP, "macvtap", "macvtap", NULL }, - { NM_LINK_TYPE_OPENVSWITCH, "openvswitch", "openvswitch", NULL }, - { NM_LINK_TYPE_TAP, "tap", NULL, NULL }, - { NM_LINK_TYPE_TUN, "tun", NULL, NULL }, - { NM_LINK_TYPE_VETH, "veth", "veth", NULL }, - { NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" }, - { NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" }, - { NM_LINK_TYPE_BNEP, "bluetooth", NULL, "bluetooth" }, + if (nh.is_present) { + /* we don't support multipath routes. */ + goto errout; + } + nh.is_present = TRUE; - { NM_LINK_TYPE_BRIDGE, "bridge", "bridge", "bridge" }, - { NM_LINK_TYPE_BOND, "bond", "bond", "bond" }, - { NM_LINK_TYPE_TEAM, "team", "team", NULL }, -}; + nh.ifindex = rtnh->rtnh_ifindex; -static const char * -nm_link_type_to_rtnl_type_string (NMLinkType type) -{ - int i; + if (rtnh->rtnh_len > sizeof(*rtnh)) { + struct nlattr *ntb[RTA_MAX + 1]; - for (i = 0; i < G_N_ELEMENTS (linktypes); i++) { - if (type == linktypes[i].nm_type) - return linktypes[i].rtnl_type; - } - g_return_val_if_reached (NULL); -} + err = nla_parse (ntb, RTA_MAX, (struct nlattr *) + RTNH_DATA(rtnh), + rtnh->rtnh_len - sizeof (*rtnh), + policy); + if (err < 0) + goto errout; -const char * -nm_link_type_to_string (NMLinkType type) -{ - int i; + if (_check_addr_or_errout (ntb, RTA_GATEWAY, addr_len)) + memcpy (&nh.gateway, nla_data (ntb[RTA_GATEWAY]), addr_len); + } - for (i = 0; i < G_N_ELEMENTS (linktypes); i++) { - if (type == linktypes[i].nm_type) - return linktypes[i].type_string; + tlen -= RTNH_ALIGN(rtnh->rtnh_len); + rtnh = RTNH_NEXT(rtnh); + } } - g_return_val_if_reached (NULL); -} -/****************************************************************** - * NMPlatform types and functions - ******************************************************************/ + if ( tb[RTA_OIF] + || tb[RTA_GATEWAY] + || tb[RTA_FLOW]) { + int ifindex = 0; + NMIPAddr gateway = NMIPAddrInit; + + if (tb[RTA_OIF]) + ifindex = nla_get_u32 (tb[RTA_OIF]); + if (_check_addr_or_errout (tb, RTA_GATEWAY, addr_len)) + memcpy (&gateway, nla_data (tb[RTA_GATEWAY]), addr_len); + + if (!nh.is_present) { + /* If no nexthops have been provided via RTA_MULTIPATH + * we add it as regular nexthop to maintain backwards + * compatibility */ + nh.ifindex = ifindex; + nh.gateway = gateway; + } else { + /* Kernel supports new style nexthop configuration, + * verify that it is a duplicate and ignore old-style nexthop. */ + if ( nh.ifindex != ifindex + || memcmp (&nh.gateway, &gateway, addr_len) != 0) + goto errout; + } + } else if (!nh.is_present) + goto errout; -typedef struct _NMLinuxPlatformPrivate NMLinuxPlatformPrivate; + /*****************************************************************/ -struct _NMLinuxPlatformPrivate { - struct nl_sock *nlh; - struct nl_sock *nlh_event; - guint32 nlh_seq_expect; - guint32 nlh_seq_last; - NMPCache *cache; - GIOChannel *event_channel; - guint event_id; + mss = 0; + if (tb[RTA_METRICS]) { + struct nlattr *mtb[RTAX_MAX + 1]; + int i; - GUdevClient *udev_client; + err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL); + if (err < 0) + goto errout; - struct { - DelayedActionType flags; - GPtrArray *list_master_connected; - GPtrArray *list_refresh_link; - gint is_handling; - guint idle_id; - } delayed_action; + for (i = 1; i <= RTAX_MAX; i++) { + if (mtb[i]) { + if (i == RTAX_ADVMSS) { + if (nla_len (mtb[i]) >= sizeof (uint32_t)) + mss = nla_get_u32(mtb[i]); + break; + } + } + } + } - GHashTable *prune_candidates; + /*****************************************************************/ - GHashTable *wifi_data; -}; + obj = nmp_object_new (is_v4 ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE, NULL); -static inline NMLinuxPlatformPrivate * -NM_LINUX_PLATFORM_GET_PRIVATE (const void *self) -{ - nm_assert (NM_IS_LINUX_PLATFORM (self)); + obj->ip_route.ifindex = nh.ifindex; - return ((NMLinuxPlatform *) self)->priv; -} + if (_check_addr_or_errout (tb, RTA_DST, addr_len)) + memcpy (obj->ip_route.network_ptr, nla_data (tb[RTA_DST]), addr_len); -G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM) + obj->ip_route.plen = rtm->rtm_dst_len; -void -nm_linux_platform_setup (void) -{ - g_object_new (NM_TYPE_LINUX_PLATFORM, - NM_PLATFORM_REGISTER_SINGLETON, TRUE, - NULL); -} + if (tb[RTA_PRIORITY]) + obj->ip_route.metric = nla_get_u32(tb[RTA_PRIORITY]); -/******************************************************************/ + if (is_v4) + obj->ip4_route.gateway = nh.gateway.addr4; + else + obj->ip6_route.gateway = nh.gateway.addr6; -NMPObjectType -_nlo_get_object_type (const struct nl_object *object) -{ - const char *type_str; + if (is_v4) + obj->ip4_route.scope_inv = nm_platform_route_scope_inv (rtm->rtm_scope); - if (!object || !(type_str = nl_object_get_type (object))) - return NMP_OBJECT_TYPE_UNKNOWN; + if (is_v4) { + if (_check_addr_or_errout (tb, RTA_PREFSRC, addr_len)) + memcpy (&obj->ip4_route.pref_src, nla_data (tb[RTA_PREFSRC]), addr_len); + } - if (!strcmp (type_str, "route/link")) - return NMP_OBJECT_TYPE_LINK; - else if (!strcmp (type_str, "route/addr")) { - switch (rtnl_addr_get_family ((struct rtnl_addr *) object)) { - case AF_INET: - return NMP_OBJECT_TYPE_IP4_ADDRESS; - case AF_INET6: - return NMP_OBJECT_TYPE_IP6_ADDRESS; - default: - return NMP_OBJECT_TYPE_UNKNOWN; - } - } else if (!strcmp (type_str, "route/route")) { - switch (rtnl_route_get_family ((struct rtnl_route *) object)) { - case AF_INET: - return NMP_OBJECT_TYPE_IP4_ROUTE; - case AF_INET6: - return NMP_OBJECT_TYPE_IP6_ROUTE; - default: - return NMP_OBJECT_TYPE_UNKNOWN; - } - } else - return NMP_OBJECT_TYPE_UNKNOWN; -} + obj->ip_route.mss = mss; -/******************************************************************/ + if (NM_FLAGS_HAS (rtm->rtm_flags, RTM_F_CLONED)) { + /* we must not straight way reject cloned routes, because we might have cached + * a non-cloned route. If we now receive an update of the route with the route + * being cloned, we must still return the object, so that we can remove the old + * one from the cache. + * + * This happens, because this route is not nmp_object_is_alive(). + * */ + obj->ip_route.source = _NM_IP_CONFIG_SOURCE_RTM_F_CLONED; + } else + obj->ip_route.source = _nm_ip_config_source_from_rtprot (rtm->rtm_protocol); -static gboolean -check_support_kernel_extended_ifa_flags (NMPlatform *platform) + obj_result = obj; + obj = NULL; +errout: + return obj_result; +} + +/** + * nmp_object_new_from_nl: + * @platform: (allow-none): for creating certain objects, the constructor wants to check + * sysfs. For this the platform instance is needed. If missing, the object might not + * be correctly detected. + * @cache: (allow-none): for certain objects, the netlink message doesn't contain all the information. + * If a cache is given, the object is completed with information from the cache. + * @nlh: the netlink message header + * @id_only: whether only to create an empty object with only the ID fields set. + * + * Returns: %NULL or a newly created NMPObject instance. + **/ +static NMPObject * +nmp_object_new_from_nl (NMPlatform *platform, const NMPCache *cache, struct nl_msg *msg, gboolean id_only) { - g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE); - - return _support_kernel_extended_ifa_flags_get (); -} + struct nlmsghdr *msghdr; -static gboolean -check_support_user_ipv6ll (NMPlatform *platform) -{ - g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE); + if (nlmsg_get_proto (msg) != NETLINK_ROUTE) + return NULL; - return _support_user_ipv6ll_get (); -} + msghdr = nlmsg_hdr (msg); -static void -process_events (NMPlatform *platform) -{ - delayed_action_handle_all (platform, TRUE); + switch (msghdr->nlmsg_type) { + case RTM_NEWLINK: + case RTM_DELLINK: + case RTM_GETLINK: + case RTM_SETLINK: + return _new_from_nl_link (platform, cache, msghdr, id_only); + case RTM_NEWADDR: + case RTM_DELADDR: + case RTM_GETADDR: + return _new_from_nl_addr (msghdr, id_only); + case RTM_NEWROUTE: + case RTM_DELROUTE: + case RTM_GETROUTE: + return _new_from_nl_route (msghdr, id_only); + default: + return NULL; + } } /******************************************************************/ -#define cache_lookup_all_objects(type, platform, obj_type, visible_only) \ - ((const type *const*) nmp_cache_lookup_multi (NM_LINUX_PLATFORM_GET_PRIVATE ((platform))->cache, \ - nmp_cache_id_init_object_type (NMP_CACHE_ID_STATIC, (obj_type), (visible_only)), \ - NULL)) +static gboolean +_nl_msg_new_link_set_afspec (struct nl_msg *msg, + int addr_gen_mode) +{ + struct nlattr *af_spec; + struct nlattr *af_attr; + nm_assert (msg); -/******************************************************************/ + if (!(af_spec = nla_nest_start (msg, IFLA_AF_SPEC))) + goto nla_put_failure; -#define DEVTYPE_PREFIX "DEVTYPE=" + if (addr_gen_mode >= 0) { + if (!(af_attr = nla_nest_start (msg, AF_INET6))) + goto nla_put_failure; -static char * -read_devtype (const char *sysfs_path) -{ - gs_free char *uevent = g_strdup_printf ("%s/uevent", sysfs_path); - char *contents = NULL; - char *cont, *end; + NLA_PUT_U8 (msg, IFLA_INET6_ADDR_GEN_MODE, addr_gen_mode); - if (!g_file_get_contents (uevent, &contents, NULL, NULL)) - return NULL; - for (cont = contents; cont; cont = end) { - end = strpbrk (cont, "\r\n"); - if (end) - *end++ = '\0'; - if (strncmp (cont, DEVTYPE_PREFIX, STRLEN (DEVTYPE_PREFIX)) == 0) { - cont += STRLEN (DEVTYPE_PREFIX); - memmove (contents, cont, strlen (cont) + 1); - return contents; - } + nla_nest_end (msg, af_attr); } - g_free (contents); - return NULL; + + nla_nest_end (msg, af_spec); + + return TRUE; +nla_put_failure: + return FALSE; } -static const NMPObject * -_lookup_link_cached (NMPlatform *platform, int ifindex, gboolean *completed_from_cache, const NMPObject **link_cached) +static gboolean +_nl_msg_new_link_set_linkinfo (struct nl_msg *msg, + NMLinkType link_type) { - const NMPObject *obj; + struct nlattr *info; + const char *kind; - nm_assert (completed_from_cache && link_cached); + nm_assert (msg); - if (!*completed_from_cache) { - obj = ifindex > 0 ? nmp_cache_lookup_link (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, ifindex) : NULL; + kind = nm_link_type_to_rtnl_type_string (link_type); + if (!kind) + goto nla_put_failure; - if (obj && !obj->_link.netlink.is_in_netlink) - *link_cached = obj; - else - *link_cached = NULL; - *completed_from_cache = TRUE; - } - return *link_cached; -} + if (!(info = nla_nest_start (msg, IFLA_LINKINFO))) + goto nla_put_failure; -static NMLinkType -link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink, gboolean *completed_from_cache, const NMPObject **link_cached, const char **out_kind) -{ - const char *rtnl_type, *ifname; - int i, arptype; + NLA_PUT_STRING (msg, IFLA_INFO_KIND, kind); - if (!rtnllink) { - if (out_kind) - *out_kind = NULL; - return NM_LINK_TYPE_NONE; - } + nla_nest_end (msg, info); - rtnl_type = rtnl_link_get_type (rtnllink); - if (!rtnl_type && completed_from_cache) { - const NMPObject *obj; + return TRUE; +nla_put_failure: + return FALSE; +} - obj = _lookup_link_cached (platform, rtnl_link_get_ifindex (rtnllink), completed_from_cache, link_cached); - if (obj && obj->link.kind) { - rtnl_type = obj->link.kind; - _LOGt ("link_extract_type(): complete kind from cache: ifindex=%d, kind=%s", rtnl_link_get_ifindex (rtnllink), rtnl_type); +static gboolean +_nl_msg_new_link_set_linkinfo_vlan (struct nl_msg *msg, + int vlan_id, + guint32 flags_mask, + guint32 flags_set, + const NMVlanQosMapping *ingress_qos, + int ingress_qos_len, + const NMVlanQosMapping *egress_qos, + int egress_qos_len) +{ + struct nlattr *info; + struct nlattr *data; + guint i; + gboolean has_any_vlan_properties = FALSE; + +#define VLAN_XGRESS_PRIO_VALID(from) (((from) & ~(guint32) 0x07) == 0) + + nm_assert (msg); + + /* We must not create an empty IFLA_LINKINFO section. Otherwise, kernel + * rejects the request as invalid. */ + if ( flags_mask != 0 + || vlan_id >= 0) + has_any_vlan_properties = TRUE; + if ( !has_any_vlan_properties + && ingress_qos && ingress_qos_len > 0) { + for (i = 0; i < ingress_qos_len; i++) { + if (VLAN_XGRESS_PRIO_VALID (ingress_qos[i].from)) { + has_any_vlan_properties = TRUE; + break; + } } } - if (out_kind) - *out_kind = rtnl_type; - if (rtnl_type) { - for (i = 0; i < G_N_ELEMENTS (linktypes); i++) { - if (g_strcmp0 (rtnl_type, linktypes[i].rtnl_type) == 0) - return linktypes[i].nm_type; + if ( !has_any_vlan_properties + && egress_qos && egress_qos_len > 0) { + for (i = 0; i < egress_qos_len; i++) { + if (VLAN_XGRESS_PRIO_VALID (egress_qos[i].to)) { + has_any_vlan_properties = TRUE; + break; + } } + } + if (!has_any_vlan_properties) + return TRUE; - if (!strcmp (rtnl_type, "tun")) { - NMPlatformTunProperties props; - guint flags; + if (!(info = nla_nest_start (msg, IFLA_LINKINFO))) + goto nla_put_failure; - if (tun_get_properties_ifname (platform, rtnl_link_get_name (rtnllink), &props)) { - if (!g_strcmp0 (props.mode, "tap")) - return NM_LINK_TYPE_TAP; - if (!g_strcmp0 (props.mode, "tun")) - return NM_LINK_TYPE_TUN; - } - flags = rtnl_link_get_flags (rtnllink); + NLA_PUT_STRING (msg, IFLA_INFO_KIND, "vlan"); - nm_log_dbg (LOGD_PLATFORM, "Failed to read tun properties for interface %d (link flags: %X)", - rtnl_link_get_ifindex (rtnllink), flags); + if (!(data = nla_nest_start (msg, IFLA_INFO_DATA))) + goto nla_put_failure; - /* try guessing the type using the link flags instead... */ - if (flags & IFF_POINTOPOINT) - return NM_LINK_TYPE_TUN; - return NM_LINK_TYPE_TAP; - } - } + if (vlan_id >= 0) + NLA_PUT_U16 (msg, IFLA_VLAN_ID, vlan_id); - arptype = rtnl_link_get_arptype (rtnllink); - if (arptype == ARPHRD_LOOPBACK) - return NM_LINK_TYPE_LOOPBACK; - else if (arptype == ARPHRD_INFINIBAND) - return NM_LINK_TYPE_INFINIBAND; + if (flags_mask != 0) { + struct ifla_vlan_flags flags = { + .flags = flags_mask & flags_set, + .mask = flags_mask, + }; - ifname = rtnl_link_get_name (rtnllink); - if (ifname) { - gs_free char *driver = NULL; - gs_free char *sysfs_path = NULL; - gs_free char *anycast_mask = NULL; - gs_free char *devtype = NULL; + NLA_PUT (msg, IFLA_VLAN_FLAGS, sizeof (flags), &flags); + } - /* Fallback OVS detection for kernel <= 3.16 */ - if (nmp_utils_ethtool_get_driver_info (ifname, &driver, NULL, NULL)) { - if (!g_strcmp0 (driver, "openvswitch")) - return NM_LINK_TYPE_OPENVSWITCH; + if (ingress_qos && ingress_qos_len > 0) { + struct nlattr *qos = NULL; - if (arptype == 256) { - /* Some s390 CTC-type devices report 256 for the encapsulation type - * for some reason, but we need to call them Ethernet. - */ - if (!g_strcmp0 (driver, "ctcm")) - return NM_LINK_TYPE_ETHERNET; + for (i = 0; i < ingress_qos_len; i++) { + /* Silently ignore invalid mappings. Kernel would truncate + * them and modify the wrong mapping. */ + if (VLAN_XGRESS_PRIO_VALID (ingress_qos[i].from)) { + if (!qos) { + if (!(qos = nla_nest_start (msg, IFLA_VLAN_INGRESS_QOS))) + goto nla_put_failure; + } + NLA_PUT (msg, i, sizeof (ingress_qos[i]), &ingress_qos[i]); } } - sysfs_path = g_strdup_printf ("/sys/class/net/%s", ifname); - anycast_mask = g_strdup_printf ("%s/anycast_mask", sysfs_path); - if (g_file_test (anycast_mask, G_FILE_TEST_EXISTS)) - return NM_LINK_TYPE_OLPC_MESH; + if (qos) + nla_nest_end (msg, qos); + } - devtype = read_devtype (sysfs_path); - for (i = 0; devtype && i < G_N_ELEMENTS (linktypes); i++) { - if (g_strcmp0 (devtype, linktypes[i].devtype) == 0) { - if (linktypes[i].nm_type == NM_LINK_TYPE_BNEP) { - /* Both BNEP and 6lowpan use DEVTYPE=bluetooth, so we must - * use arptype to distinguish between them. - */ - if (arptype != ARPHRD_ETHER) - continue; + if (egress_qos && egress_qos_len > 0) { + struct nlattr *qos = NULL; + + for (i = 0; i < egress_qos_len; i++) { + if (VLAN_XGRESS_PRIO_VALID (egress_qos[i].to)) { + if (!qos) { + if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS))) + goto nla_put_failure; } - return linktypes[i].nm_type; + NLA_PUT (msg, i, sizeof (egress_qos[i]), &egress_qos[i]); } } - /* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */ - if (wifi_utils_is_wifi (ifname, sysfs_path)) - return NM_LINK_TYPE_WIFI; - - /* Standard wired ethernet interfaces don't report an rtnl_link_type, so - * only allow fallback to Ethernet if no type is given. This should - * prevent future virtual network drivers from being treated as Ethernet - * when they should be Generic instead. - */ - if (arptype == ARPHRD_ETHER && !rtnl_type && !devtype) - return NM_LINK_TYPE_ETHERNET; + if (qos) + nla_nest_end(msg, qos); } - return NM_LINK_TYPE_UNKNOWN; + nla_nest_end (msg, data); + nla_nest_end (msg, info); + + return TRUE; +nla_put_failure: + return FALSE; } -gboolean -_nmp_vt_cmd_plobj_init_from_nl_link (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache) +static struct nl_msg * +_nl_msg_new_link (int nlmsg_type, + int nlmsg_flags, + int ifindex, + const char *ifname, + unsigned flags_mask, + unsigned flags_set) { - NMPlatformLink *obj = (NMPlatformLink *) _obj; - NMPObjectLink *obj_priv = (NMPObjectLink *) _obj; - struct rtnl_link *nlo = (struct rtnl_link *) _nlo; - const char *name; - struct nl_addr *nladdr; - const char *kind; - gboolean completed_from_cache_val = FALSE; - gboolean *completed_from_cache = complete_from_cache ? &completed_from_cache_val : NULL; - const NMPObject *link_cached = NULL; - int parent; + struct nl_msg *msg; + struct ifinfomsg ifi = { + .ifi_change = flags_mask, + .ifi_flags = flags_set, + .ifi_index = ifindex, + }; - nm_assert (memcmp (obj, ((char [sizeof (NMPObjectLink)]) { 0 }), sizeof (NMPObjectLink)) == 0); + nm_assert (NM_IN_SET (nlmsg_type, RTM_DELLINK, RTM_NEWLINK, RTM_GETLINK)); - if (_LOGt_ENABLED () && !NM_IN_SET (rtnl_link_get_family (nlo), AF_UNSPEC, AF_BRIDGE)) - _LOGt ("netlink object for ifindex %d has unusual family %d", rtnl_link_get_ifindex (nlo), rtnl_link_get_family (nlo)); + if (!(msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags))) + g_return_val_if_reached (NULL); - obj->ifindex = rtnl_link_get_ifindex (nlo); + if (nlmsg_append (msg, &ifi, sizeof (ifi), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; - if (id_only) - return TRUE; + if (ifname) + NLA_PUT_STRING (msg, IFLA_IFNAME, ifname); + + return msg; +nla_put_failure: + nlmsg_free (msg); + g_return_val_if_reached (NULL); +} + +/* Copied and modified from libnl3's build_addr_msg(). */ +static struct nl_msg * +_nl_msg_new_address (int nlmsg_type, + int nlmsg_flags, + int family, + int ifindex, + gconstpointer address, + int plen, + gconstpointer peer_address, + guint32 flags, + int scope, + guint32 lifetime, + guint32 preferred, + const char *label) +{ + struct nl_msg *msg; + struct ifaddrmsg am = { + .ifa_family = family, + .ifa_index = ifindex, + .ifa_prefixlen = plen, + .ifa_flags = flags, + }; + gsize addr_len; + + nm_assert (NM_IN_SET (family, AF_INET, AF_INET6)); + nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWADDR, RTM_DELADDR)); - name = rtnl_link_get_name (nlo); - if (name) - g_strlcpy (obj->name, name, sizeof (obj->name)); - obj->type = link_extract_type (platform, nlo, completed_from_cache, &link_cached, &kind); - obj->kind = g_intern_string (kind); - obj->flags = rtnl_link_get_flags (nlo); - obj->connected = NM_FLAGS_HAS (obj->flags, IFF_LOWER_UP); - obj->master = rtnl_link_get_master (nlo); - parent = rtnl_link_get_link (nlo); - if (parent > 0) { - gint32 link_netnsid; - - if (_rtnl_link_get_link_netnsid (nlo, &link_netnsid) == 0) - obj->parent = NM_PLATFORM_LINK_OTHER_NETNS; + msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); + if (!msg) + g_return_val_if_reached (NULL); + + if (scope == -1) { + /* Allow having scope unset, and detect the scope (including IPv4 compatibility hack). */ + if ( family == AF_INET + && address + && *((char *) address) == 127) + scope = RT_SCOPE_HOST; else - obj->parent = parent; - } - obj->mtu = rtnl_link_get_mtu (nlo); - obj->arptype = rtnl_link_get_arptype (nlo); - - if (obj->type == NM_LINK_TYPE_VLAN) { - if (!g_strcmp0 (rtnl_link_get_type (nlo), "vlan")) - obj->vlan_id = rtnl_link_vlan_get_id (nlo); - else if (completed_from_cache) { - _lookup_link_cached (platform, obj->ifindex, completed_from_cache, &link_cached); - if (link_cached) - obj->vlan_id = link_cached->link.vlan_id; - } + scope = RT_SCOPE_UNIVERSE; } + am.ifa_scope = scope, - if ((nladdr = rtnl_link_get_addr (nlo))) { - unsigned int l = 0; + addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr); - l = nl_addr_get_len (nladdr); - if (l > 0 && l <= NM_UTILS_HWADDR_LEN_MAX) { - G_STATIC_ASSERT (NM_UTILS_HWADDR_LEN_MAX == sizeof (obj->addr.data)); - memcpy (obj->addr.data, nl_addr_get_binary_addr (nladdr), l); - obj->addr.len = l; - } + if (nlmsg_append (msg, &am, sizeof (am), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + if (address) + NLA_PUT (msg, IFA_LOCAL, addr_len, address); + + if (peer_address) + NLA_PUT (msg, IFA_ADDRESS, addr_len, peer_address); + else if (address) + NLA_PUT (msg, IFA_ADDRESS, addr_len, address); + + if (label && label[0]) + NLA_PUT_STRING (msg, IFA_LABEL, label); + + if ( family == AF_INET + && nlmsg_type != RTM_DELADDR + && address + && *((in_addr_t *) address) != 0) { + in_addr_t broadcast; + + broadcast = *((in_addr_t *) address) | ~nm_utils_ip4_prefix_to_netmask (plen); + NLA_PUT (msg, IFA_BROADCAST, addr_len, &broadcast); } -#if HAVE_LIBNL_INET6_ADDR_GEN_MODE - if (_support_user_ipv6ll_get ()) { - guint8 mode = 0; + if ( lifetime != NM_PLATFORM_LIFETIME_PERMANENT + || preferred != NM_PLATFORM_LIFETIME_PERMANENT) { + struct ifa_cacheinfo ca = { + .ifa_valid = lifetime, + .ifa_prefered = preferred, + }; - if (rtnl_link_inet6_get_addr_gen_mode (nlo, &mode) == 0) - obj->inet6_addr_gen_mode_inv = _nm_platform_uint8_inv (mode); + NLA_PUT (msg, IFA_CACHEINFO, sizeof(ca), &ca); } -#endif -#if HAVE_LIBNL_INET6_TOKEN - if ((rtnl_link_inet6_get_token (nlo, &nladdr)) == 0) { - if ( nl_addr_get_family (nladdr) == AF_INET6 - && nl_addr_get_len (nladdr) == sizeof (struct in6_addr)) { - struct in6_addr *addr; - NMUtilsIPv6IfaceId *iid = &obj->inet6_token.iid; - - addr = nl_addr_get_binary_addr (nladdr); - iid->id_u8[7] = addr->s6_addr[15]; - iid->id_u8[6] = addr->s6_addr[14]; - iid->id_u8[5] = addr->s6_addr[13]; - iid->id_u8[4] = addr->s6_addr[12]; - iid->id_u8[3] = addr->s6_addr[11]; - iid->id_u8[2] = addr->s6_addr[10]; - iid->id_u8[1] = addr->s6_addr[9]; - iid->id_u8[0] = addr->s6_addr[8]; - obj->inet6_token.is_valid = TRUE; - } - nl_addr_put (nladdr); + if (flags & ~0xFF) { + /* only set the IFA_FLAGS attribute, if they actually contain additional + * flags that are not already set to am.ifa_flags. + * + * Older kernels refuse RTM_NEWADDR and RTM_NEWROUTE messages with EINVAL + * if they contain unknown netlink attributes. See net/core/rtnetlink.c, which + * was fixed by kernel commit 661d2967b3f1b34eeaa7e212e7b9bbe8ee072b59. */ + NLA_PUT_U32 (msg, IFA_FLAGS, flags); } -#endif - obj_priv->netlink.is_in_netlink = TRUE; + return msg; - return TRUE; +nla_put_failure: + nlmsg_free (msg); + g_return_val_if_reached (NULL); } -/* _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) +/* Copied and modified from libnl3's build_route_msg() and rtnl_route_build_msg(). */ +static struct nl_msg * +_nl_msg_new_route (int nlmsg_type, + int nlmsg_flags, + int family, + int ifindex, + NMIPConfigSource source, + unsigned char scope, + gconstpointer network, + int plen, + gconstpointer gateway, + guint32 metric, + guint32 mss, + gconstpointer pref_src) { - const gint64 WRAP_INTERVAL = (((gint64) G_MAXUINT32) + 1) * (1000 / 100); - gint64 timestamp_nl_ms; + struct nl_msg *msg; + struct rtmsg rtmsg = { + .rtm_family = family, + .rtm_tos = 0, + .rtm_table = RT_TABLE_MAIN, /* omit setting RTA_TABLE attribute */ + .rtm_protocol = _nm_ip_config_source_to_rtprot (source), + .rtm_scope = scope, + .rtm_type = RTN_UNICAST, + .rtm_flags = 0, + .rtm_dst_len = plen, + .rtm_src_len = 0, + }; + NMIPAddr network_clean; - /* convert timestamp from 1/100th of a second to msec. */ - timestamp_nl_ms = ((gint64) timestamp_nl) * (1000 / 100); + gsize addr_len; - /* 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; + nm_assert (NM_IN_SET (family, AF_INET, AF_INET6)); + nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWROUTE, RTM_DELROUTE)); + nm_assert (network); + + msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); + if (!msg) + g_return_val_if_reached (NULL); + + if (nlmsg_append (msg, &rtmsg, sizeof (rtmsg), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr); + + clear_host_address (family, network, plen, &network_clean); + NLA_PUT (msg, RTA_DST, addr_len, &network_clean); + + NLA_PUT_U32 (msg, RTA_PRIORITY, metric); + + if (pref_src) + NLA_PUT (msg, RTA_PREFSRC, addr_len, pref_src); + + if (mss > 0) { + struct nlattr *metrics; + + metrics = nla_nest_start (msg, RTA_METRICS); + if (!metrics) + goto nla_put_failure; + + NLA_PUT_U32 (msg, RTAX_ADVMSS, mss); + + nla_nest_end(msg, metrics); } - return timestamp_nl_ms; + /* We currently don't have need for multi-hop routes... */ + if ( gateway + && memcmp (gateway, &nm_ip_addr_zero, addr_len) != 0) + NLA_PUT (msg, RTA_GATEWAY, addr_len, gateway); + NLA_PUT_U32 (msg, RTA_OIF, ifindex); + + return msg; + +nla_put_failure: + nlmsg_free (msg); + g_return_val_if_reached (NULL); } -static guint32 -_rtnl_addr_last_update_time_to_nm (const struct rtnl_addr *rtnladdr, gint32 *out_now_nm) +/******************************************************************/ + +static int _support_kernel_extended_ifa_flags = -1; + +#define _support_kernel_extended_ifa_flags_still_undecided() (G_UNLIKELY (_support_kernel_extended_ifa_flags == -1)) + +static void +_support_kernel_extended_ifa_flags_detect (struct nl_msg *msg) { - guint32 last_update_time = rtnl_addr_get_last_update_time ((struct rtnl_addr *) rtnladdr); - struct timespec tp; - gint64 now_nl, now_nm, result; - int err; + struct nlmsghdr *msg_hdr; - /* timestamp is unset. Default to 1. */ - if (!last_update_time) { - if (out_now_nm) - *out_now_nm = 0; - return 1; + if (!_support_kernel_extended_ifa_flags_still_undecided ()) + return; + + msg_hdr = nlmsg_hdr (msg); + if (msg_hdr->nlmsg_type != RTM_NEWADDR) + return; + + /* 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). + **/ + _support_kernel_extended_ifa_flags = !!nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), 8 /* IFA_FLAGS */); + _LOG2D ("support: kernel-extended-ifa-flags: %ssupported", _support_kernel_extended_ifa_flags ? "" : "not "); +} + +static gboolean +_support_kernel_extended_ifa_flags_get (void) +{ + if (_support_kernel_extended_ifa_flags_still_undecided ()) { + _LOG2W ("support: kernel-extended-ifa-flags: unable to detect kernel support for handling IPv6 temporary addresses. Assume none"); + _support_kernel_extended_ifa_flags = 0; } + return _support_kernel_extended_ifa_flags; +} - /* do all the calculations in milliseconds scale */ +/****************************************************************** + * NMPlatform types and functions + ******************************************************************/ - err = clock_gettime (CLOCK_MONOTONIC, &tp); - g_assert (err == 0); - 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)); +typedef struct { + guint32 seq_number; + gint64 timeout_abs_ns; + WaitForNlResponseResult seq_result; + WaitForNlResponseResult *out_seq_result; +} DelayedActionWaitForNlResponseData; - result = now_nm - (now_nl - _timestamp_nl_to_ms (last_update_time, now_nl)); +typedef struct _NMLinuxPlatformPrivate NMLinuxPlatformPrivate; - if (out_now_nm) - *out_now_nm = now_nm / 1000; +struct _NMLinuxPlatformPrivate { + struct nl_sock *nlh; + guint32 nlh_seq_next; + guint32 nlh_seq_last_handled; + NMPCache *cache; + GIOChannel *event_channel; + guint event_id; - /* 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; + gboolean sysctl_get_warned; + GHashTable *sysctl_get_prev_values; - if (result > now_nm) - return now_nm / 1000; + GUdevClient *udev_client; - return result / 1000; -} + struct { + DelayedActionType flags; + GPtrArray *list_master_connected; + GPtrArray *list_refresh_link; + GArray *list_wait_for_nl_response; + gint is_handling; + } delayed_action; -static guint32 -_extend_lifetime (guint32 lifetime, guint32 seconds) -{ - guint64 v; + GHashTable *prune_candidates; - if ( lifetime == NM_PLATFORM_LIFETIME_PERMANENT - || seconds == 0) - return lifetime; + GHashTable *wifi_data; +}; + +static inline NMLinuxPlatformPrivate * +NM_LINUX_PLATFORM_GET_PRIVATE (const void *self) +{ + nm_assert (NM_IS_LINUX_PLATFORM (self)); - v = (guint64) lifetime + (guint64) seconds; - return MIN (v, NM_PLATFORM_LIFETIME_PERMANENT - 1); + return ((NMLinuxPlatform *) self)->priv; } -/* 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. - **/ -static void -_nlo_rtnl_addr_get_lifetimes (const struct rtnl_addr *rtnladdr, - guint32 *out_timestamp, - guint32 *out_lifetime, - guint32 *out_preferred) +G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM) + +void +nm_linux_platform_setup (void) { - guint32 timestamp = 0; - gint32 now; - guint32 lifetime = rtnl_addr_get_valid_lifetime ((struct rtnl_addr *) rtnladdr); - guint32 preferred = rtnl_addr_get_preferred_lifetime ((struct rtnl_addr *) rtnladdr); + g_object_new (NM_TYPE_LINUX_PLATFORM, + NM_PLATFORM_REGISTER_SINGLETON, TRUE, + NULL); +} - if ( lifetime != NM_PLATFORM_LIFETIME_PERMANENT - || preferred != NM_PLATFORM_LIFETIME_PERMANENT) { - if (preferred > lifetime) - preferred = lifetime; - timestamp = _rtnl_addr_last_update_time_to_nm (rtnladdr, &now); +/******************************************************************/ - if (now == 0) { - /* strange. failed to detect the last-update time and assumed that timestamp is 1. */ - nm_assert (timestamp == 1); - now = nm_utils_get_monotonic_timestamp_s (); - } - if (timestamp < now) { - guint32 diff = now - timestamp; +static void +_log_dbg_sysctl_set_impl (NMPlatform *platform, const char *path, const char *value) +{ + GError *error = NULL; + char *contents, *contents_escaped; + char *value_escaped = g_strescape (value, NULL); - lifetime = _extend_lifetime (lifetime, diff); - preferred = _extend_lifetime (preferred, diff); - } else - nm_assert (timestamp == now); + if (!g_file_get_contents (path, &contents, NULL, &error)) { + _LOGD ("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) + _LOGD ("sysctl: setting '%s' to '%s' (current value is identical)", path, value_escaped); + else + _LOGD ("sysctl: setting '%s' to '%s' (current value is '%s')", path, value_escaped, contents_escaped); + g_free (contents); + g_free (contents_escaped); } - *out_timestamp = timestamp; - *out_lifetime = lifetime; - *out_preferred = preferred; + g_free (value_escaped); } -gboolean -_nmp_vt_cmd_plobj_init_from_nl_ip4_address (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache) -{ - NMPlatformIP4Address *obj = (NMPlatformIP4Address *) _obj; - struct rtnl_addr *nlo = (struct rtnl_addr *) _nlo; - struct nl_addr *nladdr = rtnl_addr_get_local (nlo); - struct nl_addr *nlpeer = rtnl_addr_get_peer (nlo); - const char *label; +#define _log_dbg_sysctl_set(platform, path, value) \ + G_STMT_START { \ + if (_LOGD_ENABLED ()) { \ + _log_dbg_sysctl_set_impl (platform, path, value); \ + } \ + } G_STMT_END - if (!nladdr || nl_addr_get_len (nladdr) != sizeof (obj->address)) - g_return_val_if_reached (FALSE); +static gboolean +sysctl_set (NMPlatform *platform, const char *path, const char *value) +{ + int fd, len, nwrote, tries; + char *actual; - obj->ifindex = rtnl_addr_get_ifindex (nlo); - obj->plen = rtnl_addr_get_prefixlen (nlo); - memcpy (&obj->address, nl_addr_get_binary_addr (nladdr), sizeof (obj->address)); + g_return_val_if_fail (path != NULL, FALSE); + g_return_val_if_fail (value != NULL, FALSE); - if (id_only) - return TRUE; + /* 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, "/../")); - obj->source = NM_IP_CONFIG_SOURCE_KERNEL; - _nlo_rtnl_addr_get_lifetimes (nlo, - &obj->timestamp, - &obj->lifetime, - &obj->preferred); - if (nlpeer) { - if (nl_addr_get_len (nlpeer) != sizeof (obj->peer_address)) - g_warn_if_reached (); - else - memcpy (&obj->peer_address, nl_addr_get_binary_addr (nlpeer), sizeof (obj->peer_address)); + fd = open (path, O_WRONLY | O_TRUNC); + if (fd == -1) { + if (errno == ENOENT) { + _LOGD ("sysctl: failed to open '%s': (%d) %s", + path, errno, strerror (errno)); + } else { + _LOGE ("sysctl: failed to open '%s': (%d) %s", + path, errno, strerror (errno)); + } + return FALSE; } - label = rtnl_addr_get_label (nlo); - /* Check for ':'; we're only interested in labels used as interface aliases */ - if (label && strchr (label, ':')) - g_strlcpy (obj->label, label, sizeof (obj->label)); - return TRUE; -} + _log_dbg_sysctl_set (platform, path, value); -gboolean -_nmp_vt_cmd_plobj_init_from_nl_ip6_address (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache) -{ - NMPlatformIP6Address *obj = (NMPlatformIP6Address *) _obj; - struct rtnl_addr *nlo = (struct rtnl_addr *) _nlo; - struct nl_addr *nladdr = rtnl_addr_get_local (nlo); - struct nl_addr *nlpeer = rtnl_addr_get_peer (nlo); + /* 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); - if (!nladdr || nl_addr_get_len (nladdr) != sizeof (obj->address)) - g_return_val_if_reached (FALSE); + /* 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) { + _LOGD ("sysctl: interrupted, will try again"); + continue; + } + break; + } + } + if (nwrote == -1 && errno != EEXIST) { + _LOGE ("sysctl: failed to set '%s' to '%s': (%d) %s", + path, value, errno, strerror (errno)); + } else if (nwrote < len) { + _LOGE ("sysctl: failed to set '%s' to '%s' after three attempts", + path, value); + } + + g_free (actual); + close (fd); + return (nwrote == len); +} - obj->ifindex = rtnl_addr_get_ifindex (nlo); - obj->plen = rtnl_addr_get_prefixlen (nlo); - memcpy (&obj->address, nl_addr_get_binary_addr (nladdr), sizeof (obj->address)); +static GSList *sysctl_clear_cache_list; - if (id_only) - return TRUE; +void +_nm_linux_platform_sysctl_clear_cache (void) +{ + while (sysctl_clear_cache_list) { + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (sysctl_clear_cache_list->data); - obj->source = NM_IP_CONFIG_SOURCE_KERNEL; - _nlo_rtnl_addr_get_lifetimes (nlo, - &obj->timestamp, - &obj->lifetime, - &obj->preferred); - obj->flags = rtnl_addr_get_flags (nlo); + sysctl_clear_cache_list = g_slist_delete_link (sysctl_clear_cache_list, sysctl_clear_cache_list); - if (nlpeer) { - if (nl_addr_get_len (nlpeer) != sizeof (obj->peer_address)) - g_warn_if_reached (); - else - memcpy (&obj->peer_address, nl_addr_get_binary_addr (nlpeer), sizeof (obj->peer_address)); + g_hash_table_destroy (priv->sysctl_get_prev_values); + priv->sysctl_get_prev_values = NULL; + priv->sysctl_get_warned = FALSE; } - - return TRUE; } -gboolean -_nmp_vt_cmd_plobj_init_from_nl_ip4_route (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache) +static void +_log_dbg_sysctl_get_impl (NMPlatform *platform, const char *path, const char *contents) { - NMPlatformIP4Route *obj = (NMPlatformIP4Route *) _obj; - struct rtnl_route *nlo = (struct rtnl_route *) _nlo; - struct nl_addr *dst, *gw; - struct rtnl_nexthop *nexthop; - struct nl_addr *pref_src; + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + const char *prev_value = NULL; - if (rtnl_route_get_type (nlo) != RTN_UNICAST || - rtnl_route_get_table (nlo) != RT_TABLE_MAIN || - rtnl_route_get_tos (nlo) != 0 || - rtnl_route_get_nnexthops (nlo) != 1) - return FALSE; + if (!priv->sysctl_get_prev_values) { + sysctl_clear_cache_list = g_slist_prepend (sysctl_clear_cache_list, platform); + priv->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 (priv->sysctl_get_prev_values, path); - nexthop = rtnl_route_nexthop_n (nlo, 0); - if (!nexthop) - g_return_val_if_reached (FALSE); + 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); - dst = rtnl_route_get_dst (nlo); - if (!dst) - g_return_val_if_reached (FALSE); + _LOGD ("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 (priv->sysctl_get_prev_values, g_strdup (path), g_strdup (contents)); + } + } else { + char *contents_escaped = g_strescape (contents, NULL); - if (nl_addr_get_len (dst)) { - if (nl_addr_get_len (dst) != sizeof (obj->network)) - g_return_val_if_reached (FALSE); - memcpy (&obj->network, nl_addr_get_binary_addr (dst), sizeof (obj->network)); + _LOGD ("sysctl: reading '%s': '%s'", path, contents_escaped); + g_free (contents_escaped); + g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (path), g_strdup (contents)); } - obj->ifindex = rtnl_route_nh_get_ifindex (nexthop); - obj->plen = nl_addr_get_prefixlen (dst); - obj->metric = rtnl_route_get_priority (nlo); - obj->scope_inv = nm_platform_route_scope_inv (rtnl_route_get_scope (nlo)); - - gw = rtnl_route_nh_get_gateway (nexthop); - if (gw) { - if (nl_addr_get_len (gw) != sizeof (obj->gateway)) - g_warn_if_reached (); - else - memcpy (&obj->gateway, nl_addr_get_binary_addr (gw), sizeof (obj->gateway)); + + if ( !priv->sysctl_get_warned + && g_hash_table_size (priv->sysctl_get_prev_values) > 50000) { + _LOGW ("sysctl: the internal cache for debug-logging of sysctl values grew pretty large. You can clear it by disabling debug-logging: `nmcli general logging level KEEP domains PLATFORM:INFO`."); + priv->sysctl_get_warned = TRUE; } - rtnl_route_get_metric (nlo, RTAX_ADVMSS, &obj->mss); - if (rtnl_route_get_flags (nlo) & RTM_F_CLONED) { - /* we must not straight way reject cloned routes, because we might have cached - * a non-cloned route. If we now receive an update of the route with the route - * being cloned, we must still return the object, so that we can remove the old - * one from the cache. - * - * This happens, because this route is not nmp_object_is_alive(). - * */ - obj->source = _NM_IP_CONFIG_SOURCE_RTM_F_CLONED; - } else - obj->source = _nm_ip_config_source_from_rtprot (rtnl_route_get_protocol (nlo)); +} + +#define _log_dbg_sysctl_get(platform, path, contents) \ + G_STMT_START { \ + if (_LOGD_ENABLED ()) \ + _log_dbg_sysctl_get_impl (platform, path, contents); \ + } 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, "/../")); - pref_src = rtnl_route_get_pref_src (nlo); - if (pref_src) { - if (nl_addr_get_len (pref_src) != sizeof (obj->pref_src)) - g_warn_if_reached (); + 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)) + _LOGD ("error reading %s: %s", path, error->message); else - memcpy (&obj->pref_src, nl_addr_get_binary_addr (pref_src), sizeof (obj->pref_src)); + _LOGE ("error reading %s: %s", path, error->message); + g_clear_error (&error); + return NULL; } - return TRUE; -} + g_strstrip (contents); -gboolean -_nmp_vt_cmd_plobj_init_from_nl_ip6_route (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache) -{ - NMPlatformIP6Route *obj = (NMPlatformIP6Route *) _obj; - struct rtnl_route *nlo = (struct rtnl_route *) _nlo; - struct nl_addr *dst, *gw; - struct rtnl_nexthop *nexthop; + _log_dbg_sysctl_get (platform, path, contents); - if (rtnl_route_get_type (nlo) != RTN_UNICAST || - rtnl_route_get_table (nlo) != RT_TABLE_MAIN || - rtnl_route_get_tos (nlo) != 0 || - rtnl_route_get_nnexthops (nlo) != 1) - return FALSE; + return contents; +} - nexthop = rtnl_route_nexthop_n (nlo, 0); - if (!nexthop) - g_return_val_if_reached (FALSE); +/******************************************************************/ - dst = rtnl_route_get_dst (nlo); - if (!dst) - g_return_val_if_reached (FALSE); +static gboolean +check_support_kernel_extended_ifa_flags (NMPlatform *platform) +{ + g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE); - if (nl_addr_get_len (dst)) { - if (nl_addr_get_len (dst) != sizeof (obj->network)) - g_return_val_if_reached (FALSE); - memcpy (&obj->network, nl_addr_get_binary_addr (dst), sizeof (obj->network)); - } - obj->ifindex = rtnl_route_nh_get_ifindex (nexthop); - obj->plen = nl_addr_get_prefixlen (dst); - obj->metric = rtnl_route_get_priority (nlo); + return _support_kernel_extended_ifa_flags_get (); +} - if (id_only) - return TRUE; +static gboolean +check_support_user_ipv6ll (NMPlatform *platform) +{ + g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE); - gw = rtnl_route_nh_get_gateway (nexthop); - if (gw) { - if (nl_addr_get_len (gw) != sizeof (obj->gateway)) - g_warn_if_reached (); - else - memcpy (&obj->gateway, nl_addr_get_binary_addr (gw), sizeof (obj->gateway)); - } - rtnl_route_get_metric (nlo, RTAX_ADVMSS, &obj->mss); - if (rtnl_route_get_flags (nlo) & RTM_F_CLONED) - obj->source = _NM_IP_CONFIG_SOURCE_RTM_F_CLONED; - else - obj->source = _nm_ip_config_source_from_rtprot (rtnl_route_get_protocol (nlo)); + return _support_user_ipv6ll_get (); +} - return TRUE; +static void +process_events (NMPlatform *platform) +{ + delayed_action_handle_all (platform, TRUE); } /******************************************************************/ +#define cache_lookup_all_objects(type, platform, obj_type, visible_only) \ + ((const type *const*) nmp_cache_lookup_multi (NM_LINUX_PLATFORM_GET_PRIVATE ((platform))->cache, \ + nmp_cache_id_init_object_type (NMP_CACHE_ID_STATIC, (obj_type), (visible_only)), \ + NULL)) + +/******************************************************************/ + static void -do_emit_signal (NMPlatform *platform, const NMPObject *obj, NMPCacheOpsType cache_op, gboolean was_visible, NMPlatformReason reason) +do_emit_signal (NMPlatform *platform, const NMPObject *obj, NMPCacheOpsType cache_op, gboolean was_visible) { gboolean is_visible; NMPObject obj_clone; @@ -1476,16 +2655,21 @@ do_emit_signal (NMPlatform *platform, const NMPObject *obj, NMPCacheOpsType cach klass = NMP_OBJECT_GET_CLASS (obj); - _LOGt ("emit signal %s %s: %s (%ld)", + _LOGt ("emit signal %s %s: %s", klass->signal_type, nm_platform_signal_change_type_to_string ((NMPlatformSignalChangeType) cache_op), - nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0), - (long) reason); + nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); /* don't expose @obj directly, but clone the public fields. A signal handler might * call back into NMPlatform which could invalidate (or modify) @obj. */ memcpy (&obj_clone.object, &obj->object, klass->sizeof_public); - g_signal_emit_by_name (platform, klass->signal_type, klass->obj_type, obj_clone.object.ifindex, &obj_clone.object, (NMPlatformSignalChangeType) cache_op, reason); + g_signal_emit (platform, + _nm_platform_signal_id_get (klass->signal_type_id), + 0, + klass->obj_type, + obj_clone.object.ifindex, + &obj_clone.object, + (NMPlatformSignalChangeType) cache_op); } /******************************************************************/ @@ -1528,42 +2712,140 @@ delayed_action_to_string (DelayedActionType action_type) case DELAYED_ACTION_TYPE_REFRESH_LINK : return "refresh-link"; case DELAYED_ACTION_TYPE_MASTER_CONNECTED : return "master-connected"; case DELAYED_ACTION_TYPE_READ_NETLINK : return "read-netlink"; + case DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE : return "wait-for-nl-response"; default: return "unknown"; } } -#define _LOGt_delayed_action(action_type, arg, operation) \ - _LOGt ("delayed-action: %s %s (%d) [%p / %d]", ""operation, delayed_action_to_string (action_type), (int) action_type, arg, GPOINTER_TO_INT (arg)) +static const char * +delayed_action_to_string_full (DelayedActionType action_type, gpointer user_data, char *buf, gsize buf_size) +{ + char *buf0 = buf; + const DelayedActionWaitForNlResponseData *data; + + nm_utils_strbuf_append_str (&buf, &buf_size, delayed_action_to_string (action_type)); + switch (action_type) { + case DELAYED_ACTION_TYPE_MASTER_CONNECTED: + nm_utils_strbuf_append (&buf, &buf_size, " (master-ifindex %d)", GPOINTER_TO_INT (user_data)); + break; + case DELAYED_ACTION_TYPE_REFRESH_LINK: + nm_utils_strbuf_append (&buf, &buf_size, " (ifindex %d)", GPOINTER_TO_INT (user_data)); + break; + case DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE: + data = user_data; + + if (data) { + gint64 timeout = data->timeout_abs_ns - nm_utils_get_monotonic_timestamp_ns (); + char b[255]; + + nm_utils_strbuf_append (&buf, &buf_size, " (seq %u, timeout in %s%"G_GINT64_FORMAT".%09"G_GINT64_FORMAT"%s%s)", + data->seq_number, + timeout < 0 ? "-" : "", + (timeout < 0 ? -timeout : timeout) / NM_UTILS_NS_PER_SECOND, + (timeout < 0 ? -timeout : timeout) % NM_UTILS_NS_PER_SECOND, + data->seq_result ? ", " : "", + data->seq_result ? wait_for_nl_response_to_string (data->seq_result, b, sizeof (b)) : ""); + } else + nm_utils_strbuf_append_str (&buf, &buf_size, " (any)"); + break; + default: + nm_assert (!user_data); + break; + } + return buf0; +} + +#define _LOGt_delayed_action(action_type, user_data, operation) \ + G_STMT_START { \ + char _buf[255]; \ + \ + _LOGt ("delayed-action: %s %s", \ + ""operation, \ + delayed_action_to_string_full (action_type, user_data, _buf, sizeof (_buf))); \ + } G_STMT_END + +/*****************************************************************************/ + +static void +delayed_action_wait_for_nl_response_complete (NMPlatform *platform, + guint idx, + WaitForNlResponseResult seq_result) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + DelayedActionWaitForNlResponseData *data; + WaitForNlResponseResult *out_seq_result; + + nm_assert (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)); + nm_assert (idx < priv->delayed_action.list_wait_for_nl_response->len); + nm_assert (seq_result); + + data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, idx); + + _LOGt_delayed_action (DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, data, "complete"); + + out_seq_result = data->out_seq_result; + + g_array_remove_index_fast (priv->delayed_action.list_wait_for_nl_response, idx); + /* Note: @data is invalidated at this point */ + + if (priv->delayed_action.list_wait_for_nl_response->len <= 0) + priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE; + + if (out_seq_result) + *out_seq_result = seq_result; +} + +static void +delayed_action_wait_for_nl_response_complete_all (NMPlatform *platform, + WaitForNlResponseResult result) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + + if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) { + while (priv->delayed_action.list_wait_for_nl_response->len > 0) + delayed_action_wait_for_nl_response_complete (platform, priv->delayed_action.list_wait_for_nl_response->len - 1, result); + } + nm_assert (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)); + nm_assert (priv->delayed_action.list_wait_for_nl_response->len == 0); +} + +/*****************************************************************************/ static void delayed_action_handle_MASTER_CONNECTED (NMPlatform *platform, int master_ifindex) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - auto_nmp_obj NMPObject *obj_cache = NULL; + nm_auto_nmpobj NMPObject *obj_cache = NULL; gboolean was_visible; NMPCacheOpsType cache_op; cache_op = nmp_cache_update_link_master_connected (priv->cache, master_ifindex, &obj_cache, &was_visible, cache_pre_hook, platform); - do_emit_signal (platform, obj_cache, cache_op, was_visible, NM_PLATFORM_REASON_INTERNAL); + do_emit_signal (platform, obj_cache, cache_op, was_visible); } static void delayed_action_handle_REFRESH_LINK (NMPlatform *platform, int ifindex) { - do_request_link (platform, ifindex, NULL, FALSE); + do_request_link_no_delayed_actions (platform, ifindex, NULL); } static void delayed_action_handle_REFRESH_ALL (NMPlatform *platform, DelayedActionType flags) { - do_request_all (platform, flags, FALSE); + do_request_all_no_delayed_actions (platform, flags); } static void delayed_action_handle_READ_NETLINK (NMPlatform *platform) { - event_handler_read_netlink_all (platform, TRUE); + event_handler_read_netlink (platform, FALSE); +} + +static void +delayed_action_handle_WAIT_FOR_NL_RESPONSE (NMPlatform *platform) +{ + event_handler_read_netlink (platform, TRUE); } static gboolean @@ -1572,10 +2854,8 @@ delayed_action_handle_one (NMPlatform *platform) NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); gpointer user_data; - if (priv->delayed_action.flags == DELAYED_ACTION_TYPE_NONE) { - nm_clear_g_source (&priv->delayed_action.idle_id); + if (priv->delayed_action.flags == DELAYED_ACTION_TYPE_NONE) return FALSE; - } /* First process DELAYED_ACTION_TYPE_MASTER_CONNECTED actions. * This type of action is entirely cache-internal and is here to resolve a @@ -1622,20 +2902,30 @@ delayed_action_handle_one (NMPlatform *platform) return TRUE; } - nm_assert (priv->delayed_action.flags == DELAYED_ACTION_TYPE_REFRESH_LINK); - nm_assert (priv->delayed_action.list_refresh_link->len > 0); + if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_REFRESH_LINK)) { + nm_assert (priv->delayed_action.list_refresh_link->len > 0); - user_data = priv->delayed_action.list_refresh_link->pdata[0]; - g_ptr_array_remove_index_fast (priv->delayed_action.list_refresh_link, 0); - if (priv->delayed_action.list_refresh_link->len == 0) - priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_LINK; - nm_assert (_nm_utils_ptrarray_find_first (priv->delayed_action.list_refresh_link->pdata, priv->delayed_action.list_refresh_link->len, user_data) < 0); + user_data = priv->delayed_action.list_refresh_link->pdata[0]; + g_ptr_array_remove_index_fast (priv->delayed_action.list_refresh_link, 0); + if (priv->delayed_action.list_refresh_link->len == 0) + priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_LINK; + nm_assert (_nm_utils_ptrarray_find_first (priv->delayed_action.list_refresh_link->pdata, priv->delayed_action.list_refresh_link->len, user_data) < 0); - _LOGt_delayed_action (DELAYED_ACTION_TYPE_REFRESH_LINK, user_data, "handle"); + _LOGt_delayed_action (DELAYED_ACTION_TYPE_REFRESH_LINK, user_data, "handle"); - delayed_action_handle_REFRESH_LINK (platform, GPOINTER_TO_INT (user_data)); + delayed_action_handle_REFRESH_LINK (platform, GPOINTER_TO_INT (user_data)); - return TRUE; + return TRUE; + } + + if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) { + nm_assert (priv->delayed_action.list_wait_for_nl_response->len > 0); + _LOGt_delayed_action (DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, NULL, "handle"); + delayed_action_handle_WAIT_FOR_NL_RESPONSE (platform); + return TRUE; + } + + return FALSE; } static gboolean @@ -1644,22 +2934,18 @@ delayed_action_handle_all (NMPlatform *platform, gboolean read_netlink) NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); gboolean any = FALSE; - nm_clear_g_source (&priv->delayed_action.idle_id); + g_return_val_if_fail (priv->delayed_action.is_handling == 0, FALSE); + priv->delayed_action.is_handling++; if (read_netlink) delayed_action_schedule (platform, DELAYED_ACTION_TYPE_READ_NETLINK, NULL); while (delayed_action_handle_one (platform)) any = TRUE; priv->delayed_action.is_handling--; - return any; -} -static gboolean -delayed_action_handle_idle (gpointer user_data) -{ - NM_LINUX_PLATFORM_GET_PRIVATE (user_data)->delayed_action.idle_id = 0; - delayed_action_handle_all (user_data, FALSE); - return G_SOURCE_REMOVE; + cache_prune_candidates_prune (platform); + + return any; } static void @@ -1670,16 +2956,25 @@ delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gp nm_assert (action_type != DELAYED_ACTION_TYPE_NONE); - if (NM_FLAGS_HAS (action_type, DELAYED_ACTION_TYPE_REFRESH_LINK)) { - nm_assert (nm_utils_is_power_of_two (action_type)); + switch (action_type) { + case DELAYED_ACTION_TYPE_REFRESH_LINK: if (_nm_utils_ptrarray_find_first (priv->delayed_action.list_refresh_link->pdata, priv->delayed_action.list_refresh_link->len, user_data) < 0) g_ptr_array_add (priv->delayed_action.list_refresh_link, user_data); - } else if (NM_FLAGS_HAS (action_type, DELAYED_ACTION_TYPE_MASTER_CONNECTED)) { - nm_assert (nm_utils_is_power_of_two (action_type)); + break; + case DELAYED_ACTION_TYPE_MASTER_CONNECTED: if (_nm_utils_ptrarray_find_first (priv->delayed_action.list_master_connected->pdata, priv->delayed_action.list_master_connected->len, user_data) < 0) g_ptr_array_add (priv->delayed_action.list_master_connected, user_data); - } else + break; + case DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE: + g_array_append_vals (priv->delayed_action.list_wait_for_nl_response, user_data, 1); + break; + default: nm_assert (!user_data); + nm_assert (!NM_FLAGS_HAS (action_type, DELAYED_ACTION_TYPE_REFRESH_LINK)); + nm_assert (!NM_FLAGS_HAS (action_type, DELAYED_ACTION_TYPE_MASTER_CONNECTED)); + nm_assert (!NM_FLAGS_HAS (action_type, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)); + break; + } priv->delayed_action.flags |= action_type; @@ -1689,9 +2984,22 @@ delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gp _LOGt_delayed_action (iflags, user_data, "schedule"); } } +} + +static void +delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform, + guint32 seq_number, + WaitForNlResponseResult *out_seq_result) +{ + DelayedActionWaitForNlResponseData data = { + .seq_number = seq_number, + .timeout_abs_ns = nm_utils_get_monotonic_timestamp_ns () + (200 * (NM_UTILS_NS_PER_SECOND / 1000)), + .out_seq_result = out_seq_result, + }; - if (priv->delayed_action.is_handling == 0 && priv->delayed_action.idle_id == 0) - priv->delayed_action.idle_id = g_idle_add (delayed_action_handle_idle, platform); + delayed_action_schedule (platform, + DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE, + &data); } /******************************************************************/ @@ -1760,11 +3068,11 @@ cache_prune_candidates_prune (NMPlatform *platform) g_hash_table_iter_init (&iter, prune_candidates); while (g_hash_table_iter_next (&iter, (gpointer *)&obj, NULL)) { - auto_nmp_obj NMPObject *obj_cache = NULL; + nm_auto_nmpobj NMPObject *obj_cache = NULL; _LOGt ("cache-prune: prune %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0)); cache_op = nmp_cache_remove (priv->cache, obj, TRUE, &obj_cache, &was_visible, cache_pre_hook, platform); - do_emit_signal (platform, obj_cache, cache_op, was_visible, NM_PLATFORM_REASON_INTERNAL); + do_emit_signal (platform, obj_cache, cache_op, was_visible); } g_hash_table_unref (prune_candidates); @@ -1776,8 +3084,8 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP NMPlatform *platform = NM_PLATFORM (user_data); NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); const NMPClass *klass; - char str_buf[sizeof (_nm_platform_to_string_buffer)]; - char str_buf2[sizeof (_nm_platform_to_string_buffer)]; + char str_buf[sizeof (_nm_utils_to_string_buffer)]; + char str_buf2[sizeof (_nm_utils_to_string_buffer)]; nm_assert (old || new); nm_assert (NM_IN_SET (ops_type, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_REMOVED, NMP_CACHE_OPS_UPDATED)); @@ -1850,7 +3158,8 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP /* removal of a link could be caused by moving the link to another netns. * In this case, we potentially have to update other links that have this link as parent. - * Currently, kernel misses to sent us a notification in this case (rh #1262908). */ + * Currently, kernel misses to sent us a notification in this case + * (https://bugzilla.redhat.com/show_bug.cgi?id=1262908). */ if ( ops_type == NMP_CACHE_OPS_REMOVED && old /* <-- nonsensical, make coverity happy */ @@ -1894,6 +3203,29 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP && (new && new->_link.netlink.is_in_netlink) && (!old || !old->_link.netlink.is_in_netlink)) { + if (!new->_link.netlink.lnk) { + /* certain link-types also come with a IFLA_INFO_DATA/lnk_data. It may happen that + * kernel didn't send this notification, thus when we first learn about a link + * that lacks an lnk_data we re-request it again. + * + * For example https://bugzilla.redhat.com/show_bug.cgi?id=1284001 */ + switch (new->link.type) { + case NM_LINK_TYPE_GRE: + case NM_LINK_TYPE_IP6TNL: + case NM_LINK_TYPE_INFINIBAND: + case NM_LINK_TYPE_MACVLAN: + case NM_LINK_TYPE_MACVTAP: + case NM_LINK_TYPE_SIT: + case NM_LINK_TYPE_VLAN: + case NM_LINK_TYPE_VXLAN: + delayed_action_schedule (platform, + DELAYED_ACTION_TYPE_REFRESH_LINK, + GINT_TO_POINTER (new->link.ifindex)); + break; + default: + break; + } + } if ( new->link.type == NM_LINK_TYPE_VETH && new->link.parent == 0) { /* the initial notification when adding a veth pair can lack the parent/IFLA_LINK @@ -1959,100 +3291,74 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP } } -static NMPCacheOpsType -cache_remove_netlink (NMPlatform *platform, const NMPObject *obj_needle, NMPObject **out_obj_cache, gboolean *out_was_visible, NMPlatformReason reason) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - NMPObject *obj_cache; - gboolean was_visible; - NMPCacheOpsType cache_op; - - cache_op = nmp_cache_remove_netlink (priv->cache, obj_needle, &obj_cache, &was_visible, cache_pre_hook, platform); - do_emit_signal (platform, obj_cache, cache_op, was_visible, NM_PLATFORM_REASON_INTERNAL); - - if (out_obj_cache) - *out_obj_cache = obj_cache; - else - nmp_object_unref (obj_cache); - if (out_was_visible) - *out_was_visible = was_visible; - - return cache_op; -} +/******************************************************************/ -static NMPCacheOpsType -cache_update_netlink (NMPlatform *platform, NMPObject *obj, NMPObject **out_obj_cache, gboolean *out_was_visible, NMPlatformReason reason) +static int +_nl_send_auto_with_seq (NMPlatform *platform, + struct nl_msg *nlmsg, + WaitForNlResponseResult *out_seq_result) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - NMPObject *obj_cache; - gboolean was_visible; - NMPCacheOpsType cache_op; + guint32 seq; + int nle; - /* This is basically a convenience method to call nmp_cache_update() and do_emit_signal() - * at once. */ + /* complete the message with a sequence number (ensuring it's not zero). */ + seq = priv->nlh_seq_next++ ?: priv->nlh_seq_next++; - cache_op = nmp_cache_update_netlink (priv->cache, obj, &obj_cache, &was_visible, cache_pre_hook, platform); - do_emit_signal (platform, obj_cache, cache_op, was_visible, reason); + nlmsg_hdr (nlmsg)->nlmsg_seq = seq; - if (out_obj_cache) - *out_obj_cache = obj_cache; - else - nmp_object_unref (obj_cache); - if (out_was_visible) - *out_was_visible = was_visible; + nle = nl_send_auto (priv->nlh, nlmsg); - return cache_op; -} + if (nle >= 0) { + nle = 0; + delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result); + } else + _LOGD ("netlink: send: failed sending message: %s (%d)", nl_geterror (nle), nle); -/******************************************************************/ + return nle; +} static void -_new_sequence_number (NMPlatform *platform, guint32 seq) +do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const char *name) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - _LOGt ("_new_sequence_number(): new sequence number %u", seq); - - priv->nlh_seq_expect = seq; -} + if (name && !name[0]) + name = NULL; -static void -do_request_link (NMPlatform *platform, int ifindex, const char *name, gboolean handle_delayed_action) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - guint32 seq; + g_return_if_fail (ifindex > 0 || name); - _LOGt ("do_request_link (%d,%s)", ifindex, name ? name : ""); + _LOGD ("do-request-link: %d %s", ifindex, name ? name : ""); if (ifindex > 0) { cache_prune_candidates_record_one (platform, (NMPObject *) nmp_cache_lookup_link (priv->cache, ifindex)); } - event_handler_read_netlink_all (platform, FALSE); - - if (_nl_sock_request_link (platform, priv->nlh_event, ifindex, name, &seq) == 0) - _new_sequence_number (platform, seq); - - event_handler_read_netlink_all (platform, TRUE); + event_handler_read_netlink (platform, FALSE); - cache_prune_candidates_prune (platform); - - if (handle_delayed_action) - delayed_action_handle_all (platform, FALSE); + nlmsg = _nl_msg_new_link (RTM_GETLINK, + 0, + ifindex, + name, + 0, + 0); + if (nlmsg) + _nl_send_auto_with_seq (platform, nlmsg, NULL); } static void -do_request_one_type (NMPlatform *platform, NMPObjectType obj_type, gboolean handle_delayed_action) +do_request_link (NMPlatform *platform, int ifindex, const char *name) { - do_request_all (platform, delayed_action_refresh_from_object_type (obj_type), handle_delayed_action); + do_request_link_no_delayed_actions (platform, ifindex, name); + delayed_action_handle_all (platform, FALSE); } static void -do_request_all (NMPlatform *platform, DelayedActionType action_type, gboolean handle_delayed_action) +do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType action_type) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - guint32 seq; DelayedActionType iflags; nm_assert (!NM_FLAGS_ANY (action_type, ~DELAYED_ACTION_TYPE_REFRESH_ALL)); @@ -2066,6 +3372,12 @@ do_request_all (NMPlatform *platform, DelayedActionType action_type, gboolean ha for (iflags = (DelayedActionType) 0x1LL; iflags <= DELAYED_ACTION_TYPE_MAX; iflags <<= 1) { if (NM_FLAGS_HAS (action_type, iflags)) { NMPObjectType obj_type = delayed_action_refresh_to_object_type (iflags); + const NMPClass *klass = nmp_class_from_type (obj_type); + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct rtgenmsg gmsg = { + .rtgen_family = klass->addr_family, + }; + int nle; /* clear any delayed action that request a refresh of this object type. */ priv->delayed_action.flags &= ~iflags; @@ -2076,496 +3388,129 @@ do_request_all (NMPlatform *platform, DelayedActionType action_type, gboolean ha _LOGt_delayed_action (DELAYED_ACTION_TYPE_REFRESH_LINK, NULL, "clear (do-request-all)"); } - event_handler_read_netlink_all (platform, FALSE); - - if (_nl_sock_request_all (platform, priv->nlh_event, obj_type, &seq) == 0) - _new_sequence_number (platform, seq); - } - } - event_handler_read_netlink_all (platform, TRUE); - - cache_prune_candidates_prune (platform); - - if (handle_delayed_action) - delayed_action_handle_all (platform, FALSE); -} - -static gboolean -kernel_add_object (NMPlatform *platform, NMPObjectType obj_type, const struct nl_object *nlo) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - int nle; - - g_return_val_if_fail (nlo, FALSE); - - switch (obj_type) { - case NMP_OBJECT_TYPE_LINK: - nle = rtnl_link_add (priv->nlh, (struct rtnl_link *) nlo, NLM_F_CREATE); - break; - case NMP_OBJECT_TYPE_IP4_ADDRESS: - case NMP_OBJECT_TYPE_IP6_ADDRESS: - nle = rtnl_addr_add (priv->nlh, (struct rtnl_addr *) nlo, NLM_F_CREATE | NLM_F_REPLACE); - break; - case NMP_OBJECT_TYPE_IP4_ROUTE: - case NMP_OBJECT_TYPE_IP6_ROUTE: - nle = rtnl_route_add (priv->nlh, (struct rtnl_route *) nlo, NLM_F_CREATE | NLM_F_REPLACE); - break; - default: - g_return_val_if_reached (-NLE_INVAL); - } - - _LOGt ("kernel-add-%s: returned %s (%d)", - nmp_class_from_type (obj_type)->obj_type_name, nl_geterror (nle), -nle); - - switch (nle) { - case -NLE_SUCCESS: - return -NLE_SUCCESS; - case -NLE_EXIST: - /* NLE_EXIST is considered equivalent to success to avoid race conditions. You - * never know when something sends an identical object just before - * NetworkManager. */ - if (obj_type != NMP_OBJECT_TYPE_LINK) - return -NLE_SUCCESS; - /* fall-through */ - default: - return nle; - } -} - -static int -kernel_delete_object (NMPlatform *platform, NMPObjectType object_type, const struct nl_object *object) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - int nle; - - switch (object_type) { - case NMP_OBJECT_TYPE_LINK: - nle = rtnl_link_delete (priv->nlh, (struct rtnl_link *) object); - break; - case NMP_OBJECT_TYPE_IP4_ADDRESS: - case NMP_OBJECT_TYPE_IP6_ADDRESS: - nle = rtnl_addr_delete (priv->nlh, (struct rtnl_addr *) object, 0); - break; - case NMP_OBJECT_TYPE_IP4_ROUTE: - case NMP_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: - return NLE_SUCCESS; - case -NLE_OBJ_NOTFOUND: - _LOGt ("kernel-delete-%s: failed with \"%s\" (%d), meaning the object was already removed", - nmp_class_from_type (object_type)->obj_type_name, nl_geterror (nle), -nle); - return -NLE_SUCCESS; - case -NLE_FAILURE: - if (object_type == NMP_OBJECT_TYPE_IP6_ADDRESS) { - /* On RHEL7 kernel, deleting a non existing address fails with ENXIO (which libnl maps to NLE_FAILURE) */ - _LOGt ("kernel-delete-%s: deleting address failed with \"%s\" (%d), meaning the address was already removed", - nmp_class_from_type (object_type)->obj_type_name, nl_geterror (nle), -nle); - return NLE_SUCCESS; - } - break; - case -NLE_NOADDR: - if (object_type == NMP_OBJECT_TYPE_IP4_ADDRESS || object_type == NMP_OBJECT_TYPE_IP6_ADDRESS) { - _LOGt ("kernel-delete-%s: deleting address failed with \"%s\" (%d), meaning the address was already removed", - nmp_class_from_type (object_type)->obj_type_name, nl_geterror (nle), -nle); - return -NLE_SUCCESS; - } - break; - default: - break; - } - _LOGt ("kernel-delete-%s: failed with %s (%d)", - nmp_class_from_type (object_type)->obj_type_name, nl_geterror (nle), -nle); - return nle; -} - -static int -kernel_change_link (NMPlatform *platform, struct rtnl_link *nlo, gboolean *complete_from_cache) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - struct nl_msg *msg; - int nle; - const int nlflags = 0; - int ifindex; - - ifindex = rtnl_link_get_ifindex (nlo); - - g_return_val_if_fail (ifindex > 0, FALSE); - - /* Previously, we were using rtnl_link_change(), which builds a request based - * on the diff with an original link instance. - * - * The diff only reused ifi_family, ifi_index, ifi_flags, and name from - * the original link (see rtnl_link_build_change_request()). - * - * We don't do that anymore as we don't have an "orig" netlink instance that - * we can use. Instead the caller must ensure to properly initialize @nlo, - * especially it must set family, ifindex (or ifname) and flags. - * ifname should be set *only* if the caller wishes to change the name. - * - * @complete_from_cache is a convenience to copy the link flags over the link inside - * the platform cache. */ - - if (*complete_from_cache) { - const NMPObject *obj_cache; - - obj_cache = nmp_cache_lookup_link (priv->cache, ifindex); - if (!obj_cache || !obj_cache->_link.netlink.is_in_netlink) { - _LOGt ("kernel-change-link: failure changing link %d: cannot complete link", ifindex); - *complete_from_cache = FALSE; - return -NLE_INVAL; - } - - rtnl_link_set_flags (nlo, obj_cache->link.flags); - - /* If the caller wants to rename the link, he should explicitly set - * rtnl_link_set_name(). In all other cases, it should leave the name - * unset. Unfortunately, there is not public API in libnl to modify the - * attribute mask and clear (link->ce_mask = ~LINK_ATTR_IFNAME), so we - * require the caller to do the right thing -- i.e. don't set the name. - */ - } - - /* We don't use rtnl_link_change() because we have no original rtnl_link object - * at hand. We also don't use rtnl_link_add() because that doesn't have the - * hack to retry with RTM_SETLINK. Reimplement a mix of both. */ - - nle = rtnl_link_build_add_request (nlo, nlflags, &msg); - if (nle < 0) { - _LOGt ("kernel-change-link: failure changing link %d: cannot construct message (%s, %d)", - ifindex, nl_geterror (nle), -nle); - return nle; - } - -retry: - nle = nl_send_auto_complete (priv->nlh, msg); - if (nle < 0) - goto errout; - - nle = nl_wait_for_ack(priv->nlh); - if (nle == -NLE_OPNOTSUPP && nlmsg_hdr (msg)->nlmsg_type == RTM_NEWLINK) { - nlmsg_hdr (msg)->nlmsg_type = RTM_SETLINK; - goto retry; - } - -errout: - nlmsg_free(msg); - - /* 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: - _LOGt ("kernel-change-link: success changing link %d", ifindex); - break; - case -NLE_EXIST: - _LOGt ("kernel-change-link: success changing link %d: %s (%d)", - ifindex, nl_geterror (nle), -nle); - break; - case -NLE_OBJ_NOTFOUND: - _LOGt ("kernel-change-link: failure changing link %d: firmware not found (%s, %d)", - ifindex, nl_geterror (nle), -nle); - break; - default: - _LOGt ("kernel-change-link: failure changing link %d: netlink error (%s, %d)", - ifindex, nl_geterror (nle), -nle); - break; - } - - return nle; -} - -static void -ref_object (struct nl_object *obj, void *data) -{ - struct nl_object **out = data; - - nl_object_get (obj); - *out = obj; -} - -static int -event_seq_check (struct nl_msg *msg, gpointer user_data) -{ - NMPlatform *platform = NM_PLATFORM (user_data); - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - struct nlmsghdr *hdr; - - hdr = nlmsg_hdr (msg); - - if (hdr->nlmsg_seq == 0) - return NL_OK; - - priv->nlh_seq_last = hdr->nlmsg_seq; - - if (priv->nlh_seq_expect == 0) - _LOGt ("event_seq_check(): seq %u received (not waited)", hdr->nlmsg_seq); - else if (hdr->nlmsg_seq == priv->nlh_seq_expect) { - _LOGt ("event_seq_check(): seq %u received", hdr->nlmsg_seq); - - priv->nlh_seq_expect = 0; - } else - _LOGt ("event_seq_check(): seq %u received (wait for %u)", hdr->nlmsg_seq, priv->nlh_seq_last); - - return NL_OK; -} - -static int -event_err (struct sockaddr_nl *nla, struct nlmsgerr *nlerr, gpointer platform) -{ - _LOGt ("event_err(): error from kernel: %s (%d) for request %d", - strerror (nlerr ? -nlerr->error : 0), - nlerr ? -nlerr->error : 0, - NM_LINUX_PLATFORM_GET_PRIVATE (platform)->nlh_seq_last); - return NL_OK; -} - -/* 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); - auto_nl_object struct nl_object *nlo = NULL; - auto_nmp_obj NMPObject *obj = NULL; - struct nlmsghdr *msghdr; - char buf_nlmsg_type[16]; - - msghdr = nlmsg_hdr (msg); - - if (_support_kernel_extended_ifa_flags_still_undecided () && msghdr->nlmsg_type == RTM_NEWADDR) - _support_kernel_extended_ifa_flags_detect (msg); - - nl_msg_parse (msg, ref_object, &nlo); - if (!nlo) - return NL_OK; - - if (_support_user_ipv6ll_still_undecided() && msghdr->nlmsg_type == RTM_NEWLINK) - _support_user_ipv6ll_detect ((struct rtnl_link *) nlo); - - switch (msghdr->nlmsg_type) { - case RTM_DELADDR: - case RTM_DELLINK: - case RTM_DELROUTE: - /* The event notifies about a deleted object. We don't need to initialize all the - * fields of the nmp-object. Shortcut nmp_object_from_nl(). */ - obj = nmp_object_from_nl (platform, nlo, TRUE, TRUE); - _LOGT ("event-notification: %s, seq %u: %s", - _nl_nlmsg_type_to_str (msghdr->nlmsg_type, buf_nlmsg_type, sizeof (buf_nlmsg_type)), - msghdr->nlmsg_seq, nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ID, NULL, 0)); - break; - default: - obj = nmp_object_from_nl (platform, nlo, FALSE, TRUE); - _LOGT ("event-notification: %s, seq %u: %s", - _nl_nlmsg_type_to_str (msghdr->nlmsg_type, buf_nlmsg_type, sizeof (buf_nlmsg_type)), - msghdr->nlmsg_seq, nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - break; - } - - if (obj) { - auto_nmp_obj NMPObject *obj_cache = NULL; - - switch (msghdr->nlmsg_type) { - - case RTM_NEWLINK: - case RTM_NEWADDR: - case RTM_NEWROUTE: - cache_update_netlink (platform, obj, &obj_cache, NULL, NM_PLATFORM_REASON_EXTERNAL); - break; - - case RTM_DELLINK: - case RTM_DELADDR: - case RTM_DELROUTE: - cache_remove_netlink (platform, obj, &obj_cache, NULL, NM_PLATFORM_REASON_EXTERNAL); - break; - - default: - break; - } - - cache_prune_candidates_drop (platform, obj_cache); - } - - 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; + event_handler_read_netlink (platform, FALSE); - g_return_val_if_fail (path != NULL, FALSE); - g_return_val_if_fail (value != NULL, FALSE); + /* reimplement + * nl_rtgen_request (sk, klass->rtm_gettype, klass->addr_family, NLM_F_DUMP); + * because we need the sequence number. + */ + nlmsg = nlmsg_alloc_simple (klass->rtm_gettype, NLM_F_DUMP); + if (!nlmsg) + goto next; - /* 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, "/../")); + nle = nlmsg_append (nlmsg, &gmsg, sizeof (gmsg), NLMSG_ALIGNTO); + if (nle < 0) + goto next; - 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)); + _nl_send_auto_with_seq (platform, nlmsg, NULL); } - return FALSE; +next: + ; } +} - _log_dbg_sysctl_set (path, value); +static void +do_request_one_type (NMPlatform *platform, NMPObjectType obj_type) +{ + do_request_all_no_delayed_actions (platform, delayed_action_refresh_from_object_type (obj_type)); + delayed_action_handle_all (platform, FALSE); +} - /* 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); +static void +event_seq_check (NMPlatform *platform, struct nl_msg *msg, WaitForNlResponseResult seq_result) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + DelayedActionWaitForNlResponseData *data; + guint32 seq_number; + guint i; - /* 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; + seq_number = nlmsg_hdr (msg)->nlmsg_seq; + + if (seq_number == 0) + return; + + if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) { + nm_assert (priv->delayed_action.list_wait_for_nl_response->len > 0); + + for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; i++) { + data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i); + + if (data->seq_number == seq_number) { + /* We potentially receive many parts partial responses for the same sequence number. + * Thus, we only remember the result, and collect it later. */ + if (data->seq_result < 0) { + /* we already saw an error for this seqence number. + * Preserve it. */ + } else if ( seq_result != WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN + || data->seq_result == WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN) + data->seq_result = seq_result; + return; } - 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); + if (seq_number != priv->nlh_seq_last_handled) + _LOGt ("netlink: recvmsg: unwaited sequence number %u", seq_number); + priv->nlh_seq_last_handled = seq_number; } -static GHashTable *sysctl_get_prev_values; - static void -_log_dbg_sysctl_get_impl (const char *path, const char *contents) +event_valid_msg (NMPlatform *platform, struct nl_msg *msg) { - 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); + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + nm_auto_nmpobj NMPObject *obj = NULL; + nm_auto_nmpobj NMPObject *obj_cache = NULL; + NMPCacheOpsType cache_op; + struct nlmsghdr *msghdr; + char buf_nlmsg_type[16]; + gboolean id_only = FALSE; + gboolean was_visible; - 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); + msghdr = nlmsg_hdr (msg); - 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); + if (_support_kernel_extended_ifa_flags_still_undecided () && msghdr->nlmsg_type == RTM_NEWADDR) + _support_kernel_extended_ifa_flags_detect (msg); - 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)); + if (NM_IN_SET (msghdr->nlmsg_type, RTM_DELLINK, RTM_DELADDR, RTM_DELROUTE)) { + /* The event notifies about a deleted object. We don't need to initialize all + * fields of the object. */ + id_only = TRUE; } -} -#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 + obj = nmp_object_new_from_nl (platform, priv->cache, msg, id_only); + if (!obj) { + _LOGT ("event-notification: %s, seq %u: ignore", + _nl_nlmsg_type_to_str (msghdr->nlmsg_type, buf_nlmsg_type, sizeof (buf_nlmsg_type)), + msghdr->nlmsg_seq); + return; + } -static char * -sysctl_get (NMPlatform *platform, const char *path) -{ - GError *error = NULL; - char *contents; + _LOGT ("event-notification: %s, seq %u: %s", + _nl_nlmsg_type_to_str (msghdr->nlmsg_type, buf_nlmsg_type, sizeof (buf_nlmsg_type)), + msghdr->nlmsg_seq, nmp_object_to_string (obj, + id_only ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - /* 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, "/../")); + switch (msghdr->nlmsg_type) { - 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; - } + case RTM_NEWLINK: + case RTM_NEWADDR: + case RTM_NEWROUTE: + cache_op = nmp_cache_update_netlink (priv->cache, obj, &obj_cache, &was_visible, cache_pre_hook, platform); + do_emit_signal (platform, obj_cache, cache_op, was_visible); + break; - g_strstrip (contents); + case RTM_DELLINK: + case RTM_DELADDR: + case RTM_DELROUTE: + cache_op = nmp_cache_remove_netlink (priv->cache, obj, &obj_cache, &was_visible, cache_pre_hook, platform); + do_emit_signal (platform, obj_cache, cache_op, was_visible); + break; - _log_dbg_sysctl_get (path, contents); + default: + break; + } - return contents; + cache_prune_candidates_drop (platform, obj_cache); } /******************************************************************/ @@ -2647,195 +3592,261 @@ _nm_platform_link_get_by_address (NMPlatform *platform, return obj ? &obj->link : NULL; } -static struct nl_object * -build_rtnl_link (int ifindex, const char *name, NMLinkType type) +/*****************************************************************************/ + +static const NMPObject * +link_get_lnk (NMPlatform *platform, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link) { - struct rtnl_link *rtnllink; - int nle; + const NMPObject *obj = cache_lookup_link (platform, ifindex); - rtnllink = _nl_rtnl_link_alloc (ifindex, name); - if (type) { - nle = rtnl_link_set_type (rtnllink, nm_link_type_to_rtnl_type_string (type)); - g_assert (!nle); - } - return (struct nl_object *) rtnllink; -} + if (!obj) + return NULL; -struct nl_object * -_nmp_vt_cmd_plobj_to_nl_link (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only) -{ - const NMPlatformLink *obj = (const NMPlatformLink *) _obj; + NM_SET_OUT (out_link, &obj->link); + + if (!obj->_link.netlink.lnk) + return NULL; + if ( link_type != NM_LINK_TYPE_NONE + && ( link_type != obj->link.type + || link_type != NMP_OBJECT_GET_CLASS (obj->_link.netlink.lnk)->lnk_link_type)) + return NULL; - return build_rtnl_link (obj->ifindex, - obj->name[0] ? obj->name : NULL, - obj->type); + return obj->_link.netlink.lnk; } +/*****************************************************************************/ + static gboolean -do_add_link (NMPlatform *platform, const char *name, const struct rtnl_link *nlo) +do_add_link_with_lookup (NMPlatform *platform, + NMLinkType link_type, + const char *name, + struct nl_msg *nlmsg, + const NMPlatformLink **out_link) { - NMPObject obj_needle; + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + const NMPObject *obj = NULL; + WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; int nle; + char s_buf[256]; + + event_handler_read_netlink (platform, FALSE); - event_handler_read_netlink_all (platform, FALSE); + if (nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, NM_LINK_TYPE_NONE, NULL, NULL)) { + /* hm, a link with such a name already exists. Try reloading first. */ + do_request_link (platform, 0, name); + + obj = nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, NM_LINK_TYPE_NONE, NULL, NULL); + if (obj) { + _LOGE ("do-add-link[%s/%s]: link already exists: %s", + name, + nm_link_type_to_string (link_type), + nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ID, NULL, 0)); + return FALSE; + } + } - nle = kernel_add_object (platform, NMP_OBJECT_TYPE_LINK, (const struct nl_object *) nlo); + nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result); if (nle < 0) { - _LOGE ("do-add-link: failure adding link '%s': %s", name, nl_geterror (nle)); + _LOGE ("do-add-link[%s/%s]: failed sending netlink request \"%s\" (%d)", + name, + nm_link_type_to_string (link_type), + nl_geterror (nle), -nle); return FALSE; } - _LOGD ("do-add-link: success adding link '%s'", name); - - nmp_object_stackinit_id_link (&obj_needle, 0); - g_strlcpy (obj_needle.link.name, name, sizeof (obj_needle.link.name)); - delayed_action_handle_all (platform, TRUE); + delayed_action_handle_all (platform, FALSE); - /* FIXME: we add the link object via the second netlink socket. Sometimes, - * the notification is not yet ready via nlh_event, so we have to re-request the - * link so that it is in the cache. A better solution would be to do everything - * via one netlink socket. */ - if (!nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, 0, obj_needle.link.name, FALSE, NM_LINK_TYPE_NONE, NULL, NULL)) { - _LOGt ("do-add-link: reload: the added link is not yet ready. Request %s", obj_needle.link.name); - do_request_link (platform, 0, obj_needle.link.name, TRUE); - } + nm_assert (seq_result); - /* Return true, because kernel_add_object() succeeded. This doesn't indicate that the - * object is now actuall in the cache, because there could be a race. - * - * For that, you'd have to look at @out_obj. */ - return TRUE; -} + _NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK + ? LOGL_DEBUG + : LOGL_ERR, + "do-add-link[%s/%s]: %s", + name, + nm_link_type_to_string (link_type), + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf))); -static gboolean -do_add_link_with_lookup (NMPlatform *platform, const char *name, const struct rtnl_link *nlo, NMLinkType expected_link_type, NMPlatformLink *out_link) -{ - const NMPObject *obj; + if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) + obj = nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, link_type, NULL, NULL); - do_add_link (platform, name, nlo); + if (!obj) { + /* either kernel signaled failure, or it signaled success and the link object + * is not (yet) in the cache. Try to reload it... */ + do_request_link (platform, 0, name); + obj = nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, link_type, NULL, NULL); + } - obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, - 0, name, FALSE, expected_link_type, NULL, NULL); - if (out_link && obj) - *out_link = obj->link; + if (out_link) + *out_link = obj ? &obj->link : NULL; return !!obj; } static gboolean -do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, const struct nl_object *nlo) +do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg) { + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; int nle; + char s_buf[256]; + const NMPObject *obj; nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); - event_handler_read_netlink_all (platform, FALSE); + event_handler_read_netlink (platform, FALSE); - nle = kernel_add_object (platform, NMP_OBJECT_GET_CLASS (obj_id)->obj_type, (const struct nl_object *) nlo); + nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result); if (nle < 0) { - _LOGW ("do-add-%s: failure adding %s '%s': %s (%d)", - NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, + _LOGE ("do-add-%s[%s]: failure sending netlink request \"%s\" (%d)", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0), nl_geterror (nle), -nle); return FALSE; } - _LOGD ("do-add-%s: success adding object %s", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0)); - delayed_action_handle_all (platform, TRUE); + delayed_action_handle_all (platform, FALSE); - /* FIXME: instead of re-requesting the added object, add it via nlh_event - * so that the events are in sync. */ - if (!nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj_id)) { - _LOGt ("do-add-%s: reload: the added object is not yet ready. Request %s", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0)); - do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id), TRUE); + nm_assert (seq_result); + + _NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK + ? LOGL_DEBUG + : LOGL_ERR, + "do-add-%s[%s]: %s", + NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, + nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0), + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf))); + + /* In rare cases, the object is not yet ready as we received the ACK from + * kernel. Need to refetch. + * + * We want to safe the expensive refetch, thus we look first into the cache + * whether the object exists. + * + * FIXME: if the object already existed previously, we might not notice a + * missing update. It's not clear how to fix that reliably without refechting + * all the time. */ + obj = nmp_cache_lookup_obj (priv->cache, obj_id); + if (!obj) { + do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id)); + obj = nmp_cache_lookup_obj (priv->cache, obj_id); } - /* The return value doesn't say, whether the object is in the platform cache after adding - * it. - * Instead the return value says, whether kernel_add_object() succeeded. */ - return TRUE; + /* Adding is only successful, if kernel reported success *and* we have the + * expected object in cache afterwards. */ + return obj && seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; } - static gboolean -do_delete_object (NMPlatform *platform, const NMPObject *obj_id, const struct nl_object *nlo) +do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - auto_nl_object struct nl_object *nlo_free = NULL; + WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; int nle; + char s_buf[256]; + gboolean success = TRUE; + const char *log_detail = ""; + + event_handler_read_netlink (platform, FALSE); - event_handler_read_netlink_all (platform, FALSE); + nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result); + if (nle < 0) { + _LOGE ("do-delete-%s[%s]: failure sending netlink request \"%s\" (%d)", + NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, + nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0), + nl_geterror (nle), -nle); + goto out; + } - if (!nlo) - nlo = nlo_free = nmp_object_to_nl (platform, obj_id, FALSE); + delayed_action_handle_all (platform, FALSE); - nle = kernel_delete_object (platform, NMP_OBJECT_GET_TYPE (obj_id), nlo); - if (nle < 0) - _LOGE ("do-delete-%s: failure deleting '%s': %s (%d)", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0), nl_geterror (nle), -nle); + nm_assert (seq_result); + + if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) { + /* ok */ + } else if (NM_IN_SET (-((int) seq_result), ESRCH, ENOENT)) + log_detail = ", meaning the object was already removed"; + else if ( NM_IN_SET (-((int) seq_result), ENXIO) + && NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id), NMP_OBJECT_TYPE_IP6_ADDRESS)) { + /* On RHEL7 kernel, deleting a non existing address fails with ENXIO */ + log_detail = ", meaning the address was already removed"; + } else if ( NM_IN_SET (-((int) seq_result), EADDRNOTAVAIL) + && NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS)) + log_detail = ", meaning the address was already removed"; else - _LOGD ("do-delete-%s: success deleting '%s'", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0)); - - delayed_action_handle_all (platform, TRUE); + success = FALSE; - /* FIXME: instead of re-requesting the deleted object, add it via nlh_event - * so that the events are in sync. */ - if (NMP_OBJECT_GET_TYPE (obj_id) == NMP_OBJECT_TYPE_LINK) { - const NMPObject *obj; + _NMLOG (success ? LOGL_DEBUG : LOGL_ERR, + "do-delete-%s[%s]: %s%s", + NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, + nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0), + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)), + log_detail); - obj = nmp_cache_lookup_link_full (priv->cache, obj_id->link.ifindex, obj_id->link.ifindex <= 0 && obj_id->link.name[0] ? obj_id->link.name : NULL, FALSE, NM_LINK_TYPE_NONE, NULL, NULL); - if (obj && obj->_link.netlink.is_in_netlink) { - _LOGt ("do-delete-%s: reload: the deleted object is not yet removed. Request %s", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0)); - do_request_link (platform, obj_id->link.ifindex, obj_id->link.name, TRUE); - } - } else { - if (nmp_cache_lookup_obj (priv->cache, obj_id)) { - _LOGt ("do-delete-%s: reload: the deleted object is not yet removed. Request %s", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0)); - do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id), TRUE); - } - } +out: + if (!nmp_cache_lookup_obj (priv->cache, obj_id)) + return TRUE; - /* The return value doesn't say, whether the object is in the platform cache after adding - * it. - * Instead the return value says, whether kernel_add_object() succeeded. */ - return nle >= 0; + /* such an object still exists in the cache. To be sure, refetch it (and + * hope it's gone) */ + do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id)); + return !!nmp_cache_lookup_obj (priv->cache, obj_id); } static NMPlatformError -do_change_link (NMPlatform *platform, struct rtnl_link *nlo, gboolean complete_from_cache) +do_change_link (NMPlatform *platform, + int ifindex, + struct nl_msg *nlmsg) { + WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN; int nle; - int ifindex; - gboolean complete_from_cache2 = complete_from_cache; + char s_buf[256]; + NMPlatformError result = NM_PLATFORM_ERROR_SUCCESS; + NMLogLevel log_level = LOGL_DEBUG; + const char *log_result = "failure", *log_detail = ""; - ifindex = rtnl_link_get_ifindex (nlo); - if (ifindex <= 0) - g_return_val_if_reached (NM_PLATFORM_ERROR_BUG); +retry: + nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result); + if (nle < 0) { + _LOGE ("do-change-link[%d]: failure sending netlink request \"%s\" (%d)", + ifindex, + nl_geterror (nle), -nle); + return NM_PLATFORM_ERROR_UNSPECIFIED; + } - nle = kernel_change_link (platform, nlo, &complete_from_cache2); + /* always refetch the link after changing it. There seems to be issues + * and we sometimes lack events. Nuke it from the orbit... */ + delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (ifindex)); - switch (nle) { - case -NLE_SUCCESS: - _LOGD ("do-change-link: success changing link %d", ifindex); - break; - case -NLE_EXIST: - _LOGD ("do-change-link: success changing link %d: %s (%d)", ifindex, nl_geterror (nle), -nle); - break; - case -NLE_OBJ_NOTFOUND: - /* fall-through */ - default: - if (complete_from_cache != complete_from_cache2) - _LOGD ("do-change-link: failure changing link %d: link does not exist in cache", ifindex); - else - _LOGE ("do-change-link: failure changing link %d: %s (%d)", ifindex, nl_geterror (nle), -nle); - return nle == -NLE_OBJ_NOTFOUND ? NM_PLATFORM_ERROR_NO_FIRMWARE : NM_PLATFORM_ERROR_UNSPECIFIED; + delayed_action_handle_all (platform, FALSE); + + nm_assert (seq_result); + + if ( NM_IN_SET (-((int) seq_result), EOPNOTSUPP) + && nlmsg_hdr (nlmsg)->nlmsg_type == RTM_NEWLINK) { + nlmsg_hdr (nlmsg)->nlmsg_type = RTM_SETLINK; + goto retry; + } + + if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) { + log_result = "success"; + } else if (NM_IN_SET (-((int) seq_result), EEXIST, EADDRINUSE)) { + /* */ + } else if (NM_IN_SET (-((int) seq_result), ESRCH, ENOENT)) { + log_detail = ", firmware not found"; + result = NM_PLATFORM_ERROR_NO_FIRMWARE; + } else { + log_level = LOGL_ERR; + result = NM_PLATFORM_ERROR_UNSPECIFIED; } + _NMLOG (log_level, + "do-change-link[%d]: %s changing link: %s%s", + ifindex, + log_result, + wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)), + log_detail); - /* FIXME: as we modify the link via a separate socket, the cache is not in - * sync and we have to refetch the link. */ - do_request_link (platform, ifindex, NULL, TRUE); - return NM_PLATFORM_ERROR_SUCCESS; + return result; } static gboolean @@ -2844,9 +3855,9 @@ link_add (NMPlatform *platform, NMLinkType type, const void *address, size_t address_len, - NMPlatformLink *out_link) + const NMPlatformLink **out_link) { - auto_nl_object struct nl_object *l = NULL; + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; if (type == NM_LINK_TYPE_BOND) { /* When the kernel loads the bond module, either via explicit modprobe @@ -2860,34 +3871,50 @@ link_add (NMPlatform *platform, nm_utils_modprobe (NULL, TRUE, "bonding", "max_bonds=0", NULL); } - debug ("link: add link '%s' of type '%s' (%d)", + _LOGD ("link: add link '%s' of type '%s' (%d)", name, nm_link_type_to_string (type), (int) type); - l = build_rtnl_link (0, name, type); + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE, + 0, + name, + 0, + 0); + if (!nlmsg) + return FALSE; - g_assert ( (address != NULL) ^ (address_len == 0) ); - if (address) { - auto_nl_addr struct nl_addr *nladdr = _nl_addr_build (AF_LLC, address, address_len); + if (address && address_len) + NLA_PUT (nlmsg, IFLA_ADDRESS, address_len, address); - rtnl_link_set_addr ((struct rtnl_link *) l, nladdr); - } + if (!_nl_msg_new_link_set_linkinfo (nlmsg, type)) + return FALSE; - return do_add_link_with_lookup (platform, name, (struct rtnl_link *) l, type, out_link); + return do_add_link_with_lookup (platform, type, name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); } static gboolean link_delete (NMPlatform *platform, int ifindex) { + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - NMPObject obj_needle; + NMPObject obj_id; const NMPObject *obj; obj = nmp_cache_lookup_link (priv->cache, ifindex); if (!obj || !obj->_link.netlink.is_in_netlink) return FALSE; - nmp_object_stackinit_id_link (&obj_needle, ifindex); - return do_delete_object (platform, &obj_needle, NULL); + nlmsg = _nl_msg_new_link (RTM_DELLINK, + 0, + ifindex, + NULL, + 0, + 0); + + nmp_object_stackinit_id_link (&obj_id, ifindex); + return do_delete_object (platform, &obj_id, nlmsg); } static const char * @@ -2933,33 +3960,35 @@ link_get_unmanaged (NMPlatform *platform, int ifindex, gboolean *unmanaged) static gboolean link_refresh (NMPlatform *platform, int ifindex) { - do_request_link (platform, ifindex, NULL, TRUE); + do_request_link (platform, ifindex, NULL); return !!cache_lookup_link (platform, ifindex); } static NMPlatformError -link_change_flags (NMPlatform *platform, int ifindex, unsigned int flags, gboolean value) -{ - auto_nl_object struct rtnl_link *change = _nl_rtnl_link_alloc (ifindex, NULL); - const NMPObject *obj_cache; - char buf[256]; - - obj_cache = cache_lookup_link (platform, ifindex); - if (!obj_cache) - return NM_PLATFORM_ERROR_NOT_FOUND; - - rtnl_link_set_flags (change, obj_cache->link.flags); - if (value) - rtnl_link_set_flags (change, flags); - else - rtnl_link_unset_flags (change, flags); - - _LOGD ("link: change %d: flags %s '%s' (%d)", ifindex, - value ? "set" : "unset", - rtnl_link_flags2str (flags, buf, sizeof (buf)), - flags); - - return do_change_link (platform, change, FALSE); +link_change_flags (NMPlatform *platform, + int ifindex, + unsigned flags_mask, + unsigned flags_set) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + char s_flags[100]; + + _LOGD ("link: change %d: flags: set 0x%x/0x%x ([%s] / [%s])", + ifindex, + flags_set, + flags_mask, + nm_platform_link_flags2str (flags_set, s_flags, sizeof (s_flags)), + nm_platform_link_flags2str (flags_mask, NULL, 0)); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + 0, + ifindex, + NULL, + flags_mask, + flags_set); + if (!nlmsg) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return do_change_link (platform, ifindex, nlmsg); } static gboolean @@ -2967,7 +3996,7 @@ link_set_up (NMPlatform *platform, int ifindex, gboolean *out_no_firmware) { NMPlatformError plerr; - plerr = link_change_flags (platform, ifindex, IFF_UP, TRUE); + plerr = link_change_flags (platform, ifindex, IFF_UP, IFF_UP); if (out_no_firmware) *out_no_firmware = plerr == NM_PLATFORM_ERROR_NO_FIRMWARE; return plerr == NM_PLATFORM_ERROR_SUCCESS; @@ -2976,19 +4005,19 @@ link_set_up (NMPlatform *platform, int ifindex, gboolean *out_no_firmware) static gboolean link_set_down (NMPlatform *platform, int ifindex) { - return link_change_flags (platform, ifindex, IFF_UP, FALSE) == NM_PLATFORM_ERROR_SUCCESS; + return link_change_flags (platform, ifindex, IFF_UP, 0) == NM_PLATFORM_ERROR_SUCCESS; } static gboolean link_set_arp (NMPlatform *platform, int ifindex) { - return link_change_flags (platform, ifindex, IFF_NOARP, FALSE) == NM_PLATFORM_ERROR_SUCCESS; + return link_change_flags (platform, ifindex, IFF_NOARP, 0) == NM_PLATFORM_ERROR_SUCCESS; } static gboolean link_set_noarp (NMPlatform *platform, int ifindex) { - return link_change_flags (platform, ifindex, IFF_NOARP, TRUE) == NM_PLATFORM_ERROR_SUCCESS; + return link_change_flags (platform, ifindex, IFF_NOARP, IFF_NOARP) == NM_PLATFORM_ERROR_SUCCESS; } static const char * @@ -3020,19 +4049,30 @@ link_get_udev_device (NMPlatform *platform, int ifindex) static gboolean link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enabled) { -#if HAVE_LIBNL_INET6_ADDR_GEN_MODE - if (_support_user_ipv6ll_get ()) { - auto_nl_object struct rtnl_link *nlo = _nl_rtnl_link_alloc (ifindex, NULL); - guint8 mode = enabled ? IN6_ADDR_GEN_MODE_NONE : IN6_ADDR_GEN_MODE_EUI64; - char buf[32]; + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + guint8 mode = enabled ? NM_IN6_ADDR_GEN_MODE_NONE : NM_IN6_ADDR_GEN_MODE_EUI64; - rtnl_link_inet6_set_addr_gen_mode (nlo, mode); - debug ("link: change %d: set IPv6 address generation mode to %s", - ifindex, rtnl_link_inet6_addrgenmode2str (mode, buf, sizeof (buf))); - return do_change_link (platform, nlo, TRUE) == NM_PLATFORM_ERROR_SUCCESS; + if (!_support_user_ipv6ll_get ()) { + _LOGD ("link: change %d: user-ipv6ll: not supported", ifindex); + return FALSE; } -#endif - return FALSE; + + _LOGD ("link: change %d: user-ipv6ll: set IPv6 address generation mode to %s", + ifindex, + nm_platform_link_inet6_addrgenmode2str (mode, NULL, 0)); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + 0, + ifindex, + NULL, + 0, + 0); + if ( !nlmsg + || !_nl_msg_new_link_set_afspec (nlmsg, + mode)) + g_return_val_if_reached (FALSE); + + return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS; } static gboolean @@ -3067,16 +4107,30 @@ link_supports_vlans (NMPlatform *platform, int ifindex) static gboolean link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size_t length) { - auto_nl_object struct rtnl_link *change = _nl_rtnl_link_alloc (ifindex, NULL); - auto_nl_addr struct nl_addr *nladdr = _nl_addr_build (AF_LLC, address, length); + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; gs_free char *mac = NULL; - rtnl_link_set_addr (change, nladdr); + if (!address || !length) + g_return_val_if_reached (FALSE); - _LOGD ("link: change %d: address %s (%lu bytes)", ifindex, + _LOGD ("link: change %d: address: %s (%lu bytes)", ifindex, (mac = nm_utils_hwaddr_ntoa (address, length)), (unsigned long) length); - return do_change_link (platform, change, TRUE) == NM_PLATFORM_ERROR_SUCCESS; + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + 0, + ifindex, + NULL, + 0, + 0); + if (!nlmsg) + return FALSE; + + NLA_PUT (nlmsg, IFLA_ADDRESS, length, address); + + return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS; +nla_put_failure: + g_return_val_if_reached (FALSE); } static gboolean @@ -3091,12 +4145,24 @@ link_get_permanent_address (NMPlatform *platform, static gboolean link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu) { - auto_nl_object struct rtnl_link *change = _nl_rtnl_link_alloc (ifindex, NULL); + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + + _LOGD ("link: change %d: mtu: %u", ifindex, (unsigned) mtu); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + 0, + ifindex, + NULL, + 0, + 0); + if (!nlmsg) + return FALSE; - rtnl_link_set_mtu (change, mtu); - debug ("link: change %d: mtu %lu", ifindex, (unsigned long)mtu); + NLA_PUT_U32 (nlmsg, IFLA_MTU, mtu); - return do_change_link (platform, change, TRUE) == NM_PLATFORM_ERROR_SUCCESS; + return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS; +nla_put_failure: + g_return_val_if_reached (FALSE); } static char * @@ -3148,649 +4214,680 @@ vlan_add (NMPlatform *platform, int parent, int vlan_id, guint32 vlan_flags, - NMPlatformLink *out_link) -{ - auto_nl_object struct rtnl_link *rtnllink = (struct rtnl_link *) build_rtnl_link (0, name, NM_LINK_TYPE_VLAN); - 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 do_add_link_with_lookup (platform, name, rtnllink, NM_LINK_TYPE_VLAN, out_link); -} - -static gboolean -vlan_get_info (NMPlatform *platform, int ifindex, int *parent, int *vlan_id) -{ - const NMPObject *obj = cache_lookup_link (platform, ifindex); - int p = 0, v = 0; - - if (obj) { - p = obj->link.parent; - v = obj->link.vlan_id; - } - if (parent) - *parent = p; - if (vlan_id) - *vlan_id = v; - return !!obj; -} - -static gboolean -vlan_set_ingress_map (NMPlatform *platform, int ifindex, int from, int to) -{ - auto_nl_object struct rtnl_link *change = (struct rtnl_link *) build_rtnl_link (ifindex, NULL, NM_LINK_TYPE_VLAN); - - rtnl_link_set_type (change, "vlan"); - rtnl_link_vlan_set_ingress_map (change, from, to); - - debug ("link: change %d: vlan ingress map %d -> %d", ifindex, from, to); - - return do_change_link (platform, change, TRUE) == NM_PLATFORM_ERROR_SUCCESS; -} - -static gboolean -vlan_set_egress_map (NMPlatform *platform, int ifindex, int from, int to) + const NMPlatformLink **out_link) { - auto_nl_object struct rtnl_link *change = (struct rtnl_link *) build_rtnl_link (ifindex, NULL, NM_LINK_TYPE_VLAN); + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - rtnl_link_set_type (change, "vlan"); - rtnl_link_vlan_set_egress_map (change, from, to); + G_STATIC_ASSERT (NM_VLAN_FLAG_REORDER_HEADERS == (guint32) VLAN_FLAG_REORDER_HDR); + G_STATIC_ASSERT (NM_VLAN_FLAG_GVRP == (guint32) VLAN_FLAG_GVRP); + G_STATIC_ASSERT (NM_VLAN_FLAG_LOOSE_BINDING == (guint32) VLAN_FLAG_LOOSE_BINDING); + G_STATIC_ASSERT (NM_VLAN_FLAG_MVRP == (guint32) VLAN_FLAG_MVRP); - debug ("link: change %d: vlan egress map %d -> %d", ifindex, from, to); + vlan_flags &= (guint32) NM_VLAN_FLAGS_ALL; - return do_change_link (platform, change, TRUE) == NM_PLATFORM_ERROR_SUCCESS; -} + _LOGD ("link: add vlan '%s', parent %d, vlan id %d, flags %X", + name, parent, vlan_id, (unsigned int) vlan_flags); -static gboolean -link_enslave (NMPlatform *platform, int master, int slave) -{ - auto_nl_object struct rtnl_link *change = _nl_rtnl_link_alloc (slave, NULL); + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE, + 0, + name, + 0, + 0); + if (!nlmsg) + return FALSE; - rtnl_link_set_master (change, master); - debug ("link: change %d: enslave to master %d", slave, master); + NLA_PUT_U32 (nlmsg, IFLA_LINK, parent); - return do_change_link (platform, change, TRUE) == NM_PLATFORM_ERROR_SUCCESS; -} + if (!_nl_msg_new_link_set_linkinfo_vlan (nlmsg, + vlan_id, + NM_VLAN_FLAGS_ALL, + vlan_flags, + NULL, + 0, + NULL, + 0)) + return FALSE; -static gboolean -link_release (NMPlatform *platform, int master, int slave) -{ - return link_enslave (platform, 0, slave); + return do_add_link_with_lookup (platform, NM_LINK_TYPE_VLAN, name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); } -static char * -link_option_path (NMPlatform *platform, int master, const char *category, const char *option) -{ - const char *name = nm_platform_link_get_name (platform, master); - - if (!name || !category || !option) - return NULL; +static int +link_gre_add (NMPlatform *platform, + const char *name, + const NMPlatformLnkGre *props, + const NMPlatformLink **out_link) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *info; + struct nlattr *data; + char buffer[INET_ADDRSTRLEN]; + + _LOGD (LOG_FMT_IP_TUNNEL, + "gre", + name, + props->parent_ifindex, + nm_utils_inet4_ntop (props->local, NULL), + nm_utils_inet4_ntop (props->remote, buffer)); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE, + 0, + name, + 0, + 0); + if (!nlmsg) + return FALSE; - 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)); -} + if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) + goto nla_put_failure; -static gboolean -link_set_option (NMPlatform *platform, int master, const char *category, const char *option, const char *value) -{ - gs_free char *path = link_option_path (platform, master, category, option); + NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "gre"); - return path && nm_platform_sysctl_set (platform, path, value); -} + if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) + goto nla_put_failure; -static char * -link_get_option (NMPlatform *platform, int master, const char *category, const char *option) -{ - gs_free char *path = link_option_path (platform, master, category, option); + if (props->parent_ifindex) + NLA_PUT_U32 (nlmsg, IFLA_GRE_LINK, props->parent_ifindex); + NLA_PUT_U32 (nlmsg, IFLA_GRE_LOCAL, props->local); + NLA_PUT_U32 (nlmsg, IFLA_GRE_REMOTE, props->remote); + NLA_PUT_U8 (nlmsg, IFLA_GRE_TTL, props->ttl); + NLA_PUT_U8 (nlmsg, IFLA_GRE_TOS, props->tos); + NLA_PUT_U8 (nlmsg, IFLA_GRE_PMTUDISC, !!props->path_mtu_discovery); + NLA_PUT_U32 (nlmsg, IFLA_GRE_IKEY, htonl (props->input_key)); + NLA_PUT_U32 (nlmsg, IFLA_GRE_OKEY, htonl (props->output_key)); + NLA_PUT_U32 (nlmsg, IFLA_GRE_IFLAGS, htons (props->input_flags)); + NLA_PUT_U32 (nlmsg, IFLA_GRE_OFLAGS, htons (props->output_flags)); - return path ? nm_platform_sysctl_get (platform, path) : NULL; -} + nla_nest_end (nlmsg, data); + nla_nest_end (nlmsg, info); -static const char * -master_category (NMPlatform *platform, int master) -{ - switch (nm_platform_link_get_type (platform, master)) { - case NM_LINK_TYPE_BRIDGE: - return "bridge"; - case NM_LINK_TYPE_BOND: - return "bonding"; - default: - return NULL; - } + return do_add_link_with_lookup (platform, NM_LINK_TYPE_GRE, name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); } -static const char * -slave_category (NMPlatform *platform, int slave) -{ - int master = nm_platform_link_get_master (platform, slave); +static int +link_ip6tnl_add (NMPlatform *platform, + const char *name, + const NMPlatformLnkIp6Tnl *props, + const NMPlatformLink **out_link) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *info; + struct nlattr *data; + char buffer[INET_ADDRSTRLEN]; + guint32 flowinfo; + + _LOGD (LOG_FMT_IP_TUNNEL, + "ip6tnl", + name, + props->parent_ifindex, + nm_utils_inet6_ntop (&props->local, NULL), + nm_utils_inet6_ntop (&props->remote, buffer)); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE, + 0, + name, + 0, + 0); + if (!nlmsg) + return FALSE; - if (master <= 0) - return NULL; + if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) + goto nla_put_failure; - switch (nm_platform_link_get_type (platform, master)) { - case NM_LINK_TYPE_BRIDGE: - return "brport"; - default: - return NULL; - } -} + NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "ip6tnl"); -static gboolean -master_set_option (NMPlatform *platform, int master, const char *option, const char *value) -{ - return link_set_option (platform, master, master_category (platform, master), option, value); -} + if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) + goto nla_put_failure; -static char * -master_get_option (NMPlatform *platform, int master, const char *option) -{ - return link_get_option (platform, master, master_category (platform, master), option); -} + if (props->parent_ifindex) + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex); -static gboolean -slave_set_option (NMPlatform *platform, int slave, const char *option, const char *value) -{ - return link_set_option (platform, slave, slave_category (platform, slave), option, value); -} + if (memcmp (&props->local, &in6addr_any, sizeof (in6addr_any))) + NLA_PUT (nlmsg, IFLA_IPTUN_LOCAL, sizeof (props->local), &props->local); + if (memcmp (&props->remote, &in6addr_any, sizeof (in6addr_any))) + NLA_PUT (nlmsg, IFLA_IPTUN_REMOTE, sizeof (props->remote), &props->remote); -static char * -slave_get_option (NMPlatform *platform, int slave, const char *option) -{ - return link_get_option (platform, slave, slave_category (platform, slave), option); -} + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_ENCAP_LIMIT, props->encap_limit); -static gboolean -infiniband_partition_add (NMPlatform *platform, int parent, int p_key, NMPlatformLink *out_link) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - const NMPObject *obj_parent; - const NMPObject *obj; - gs_free char *path = NULL; - gs_free char *id = NULL; - gs_free char *ifname = NULL; + flowinfo = props->flow_label & IP6_FLOWINFO_FLOWLABEL_MASK; + flowinfo |= (props->tclass << IP6_FLOWINFO_TCLASS_SHIFT) + & IP6_FLOWINFO_TCLASS_MASK; + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_FLOWINFO, htonl (flowinfo)); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PROTO, props->proto); - obj_parent = nmp_cache_lookup_link (priv->cache, parent); - if (!obj_parent || !obj_parent->link.name[0]) - g_return_val_if_reached (FALSE); + nla_nest_end (nlmsg, data); + nla_nest_end (nlmsg, info); - ifname = g_strdup_printf ("%s.%04x", obj_parent->link.name, p_key); + return do_add_link_with_lookup (platform, NM_LINK_TYPE_IP6TNL, name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); +} - path = g_strdup_printf ("/sys/class/net/%s/create_child", ASSERT_VALID_PATH_COMPONENT (obj_parent->link.name)); - id = g_strdup_printf ("0x%04x", p_key); - if (!nm_platform_sysctl_set (platform, path, id)) +static int +link_ipip_add (NMPlatform *platform, + const char *name, + const NMPlatformLnkIpIp *props, + const NMPlatformLink **out_link) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *info; + struct nlattr *data; + char buffer[INET_ADDRSTRLEN]; + + _LOGD (LOG_FMT_IP_TUNNEL, + "ipip", + name, + props->parent_ifindex, + nm_utils_inet4_ntop (props->local, NULL), + nm_utils_inet4_ntop (props->remote, buffer)); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE, + 0, + name, + 0, + 0); + if (!nlmsg) return FALSE; - do_request_link (platform, 0, ifname, TRUE); + if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) + goto nla_put_failure; - obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, - 0, ifname, FALSE, NM_LINK_TYPE_INFINIBAND, NULL, NULL); - if (out_link && obj) - *out_link = obj->link; - return !!obj; -} + NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "ipip"); -typedef struct { - int p_key; - const char *mode; -} IpoibInfo; + if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) + goto nla_put_failure; -/* IFLA_IPOIB_* were introduced in the 3.7 kernel, but the kernel headers - * we're building against might not have those properties even though the - * running kernel might. - */ -#define IFLA_IPOIB_UNSPEC 0 -#define IFLA_IPOIB_PKEY 1 -#define IFLA_IPOIB_MODE 2 -#define IFLA_IPOIB_UMCAST 3 -#undef IFLA_IPOIB_MAX -#define IFLA_IPOIB_MAX IFLA_IPOIB_UMCAST + if (props->parent_ifindex) + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex); + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LOCAL, props->local); + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_REMOTE, props->remote); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TOS, props->tos); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery); -#define IPOIB_MODE_DATAGRAM 0 /* using unreliable datagram QPs */ -#define IPOIB_MODE_CONNECTED 1 /* using connected QPs */ + nla_nest_end (nlmsg, data); + nla_nest_end (nlmsg, info); -static const struct nla_policy infiniband_info_policy[IFLA_IPOIB_MAX + 1] = { - [IFLA_IPOIB_PKEY] = { .type = NLA_U16 }, - [IFLA_IPOIB_MODE] = { .type = NLA_U16 }, - [IFLA_IPOIB_UMCAST] = { .type = NLA_U16 }, -}; + return do_add_link_with_lookup (platform, NM_LINK_TYPE_IPIP, name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); +} static int -infiniband_info_data_parser (struct nlattr *info_data, gpointer parser_data) -{ - IpoibInfo *info = parser_data; - struct nlattr *tb[IFLA_MACVLAN_MAX + 1]; - int err; +link_macvlan_add (NMPlatform *platform, + const char *name, + int parent, + const NMPlatformLnkMacvlan *props, + const NMPlatformLink **out_link) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *info; + struct nlattr *data; + + _LOGD ("adding %s '%s' parent %u mode %u", + props->tap ? "macvtap" : "macvlan", + name, + parent, + props->mode); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE, + 0, + name, + 0, + 0); + if (!nlmsg) + return FALSE; - err = nla_parse_nested (tb, IFLA_IPOIB_MAX, info_data, - (struct nla_policy *) infiniband_info_policy); - if (err < 0) - return err; - if (!tb[IFLA_IPOIB_PKEY] || !tb[IFLA_IPOIB_MODE]) - return -EINVAL; + NLA_PUT_U32 (nlmsg, IFLA_LINK, parent); - info->p_key = nla_get_u16 (tb[IFLA_IPOIB_PKEY]); + if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) + goto nla_put_failure; - switch (nla_get_u16 (tb[IFLA_IPOIB_MODE])) { - case IPOIB_MODE_DATAGRAM: - info->mode = "datagram"; - break; - case IPOIB_MODE_CONNECTED: - info->mode = "connected"; - break; - default: - return -NLE_PARSE_ERR; - } + NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, props->tap ? "macvtap" : "macvlan"); - return 0; -} + if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) + goto nla_put_failure; -static gboolean -infiniband_get_info (NMPlatform *platform, int ifindex, int *parent, int *p_key, const char **mode) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - const NMPObject *obj; - IpoibInfo info = { -1, NULL }; + NLA_PUT_U32 (nlmsg, IFLA_MACVLAN_MODE, props->mode); + NLA_PUT_U16 (nlmsg, IFLA_MACVLAN_FLAGS, props->no_promisc ? MACVLAN_FLAG_NOPROMISC : 0); - obj = cache_lookup_link (platform, ifindex); - if (!obj) + nla_nest_end (nlmsg, data); + nla_nest_end (nlmsg, info); + + return do_add_link_with_lookup (platform, + props->tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN, + name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); +} + +static int +link_sit_add (NMPlatform *platform, + const char *name, + const NMPlatformLnkSit *props, + const NMPlatformLink **out_link) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *info; + struct nlattr *data; + char buffer[INET_ADDRSTRLEN]; + + _LOGD (LOG_FMT_IP_TUNNEL, + "sit", + name, + props->parent_ifindex, + nm_utils_inet4_ntop (props->local, NULL), + nm_utils_inet4_ntop (props->remote, buffer)); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE, + 0, + name, + 0, + 0); + if (!nlmsg) return FALSE; - if (parent) - *parent = obj->link.parent; - - if (_nl_link_parse_info_data (priv->nlh, - ifindex, - infiniband_info_data_parser, - &info) != 0) { - const char *iface = obj->link.name; - char *path, *contents = NULL; - - /* Fall back to reading sysfs */ - path = g_strdup_printf ("/sys/class/net/%s/mode", ASSERT_VALID_PATH_COMPONENT (iface)); - contents = nm_platform_sysctl_get (platform, path); - g_free (path); - if (!contents) - return FALSE; + if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) + goto nla_put_failure; - if (strstr (contents, "datagram")) - info.mode = "datagram"; - else if (strstr (contents, "connected")) - info.mode = "connected"; - g_free (contents); + NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "sit"); - path = g_strdup_printf ("/sys/class/net/%s/pkey", ASSERT_VALID_PATH_COMPONENT (iface)); - contents = nm_platform_sysctl_get (platform, path); - g_free (path); - if (!contents) - return FALSE; + if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) + goto nla_put_failure; - info.p_key = (int) _nm_utils_ascii_str_to_int64 (contents, 16, 0, 0xFFFF, -1); - g_free (contents); + if (props->parent_ifindex) + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LINK, props->parent_ifindex); + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_LOCAL, props->local); + NLA_PUT_U32 (nlmsg, IFLA_IPTUN_REMOTE, props->remote); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TTL, props->ttl); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_TOS, props->tos); + NLA_PUT_U8 (nlmsg, IFLA_IPTUN_PMTUDISC, !!props->path_mtu_discovery); - if (info.p_key < 0) - return FALSE; - } + nla_nest_end (nlmsg, data); + nla_nest_end (nlmsg, info); - if (p_key) - *p_key = info.p_key; - if (mode) - *mode = info.mode; - return TRUE; + return do_add_link_with_lookup (platform, NM_LINK_TYPE_SIT, name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); } static gboolean -veth_get_properties (NMPlatform *platform, int ifindex, NMPlatformVethProperties *props) +link_vxlan_add (NMPlatform *platform, + const char *name, + const NMPlatformLnkVxlan *props, + const NMPlatformLink **out_link) { - const char *ifname; - int peer_ifindex; + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + struct nlattr *info; + struct nlattr *data; + struct nm_ifla_vxlan_port_range port_range; - ifname = nm_platform_link_get_name (platform, ifindex); - if (!ifname) - return FALSE; + g_return_val_if_fail (props, FALSE); + + _LOGD ("link: add vxlan '%s', parent %d, vxlan id %d", + name, props->parent_ifindex, props->id); - peer_ifindex = nmp_utils_ethtool_get_peer_ifindex (ifname); - if (peer_ifindex <= 0) + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + NLM_F_CREATE, + 0, + name, + 0, + 0); + if (!nlmsg) return FALSE; - props->peer = peer_ifindex; - return TRUE; -} + if (!(info = nla_nest_start (nlmsg, IFLA_LINKINFO))) + goto nla_put_failure; -static gboolean -tun_get_properties_ifname (NMPlatform *platform, const char *ifname, NMPlatformTunProperties *props) -{ - char *path, *val; - gboolean success = TRUE; + NLA_PUT_STRING (nlmsg, IFLA_INFO_KIND, "vxlan"); - g_return_val_if_fail (props, FALSE); + if (!(data = nla_nest_start (nlmsg, IFLA_INFO_DATA))) + goto nla_put_failure; - memset (props, 0, sizeof (*props)); - props->owner = -1; - props->group = -1; + NLA_PUT_U32 (nlmsg, IFLA_VXLAN_ID, props->id); - if (!ifname || !nm_utils_iface_valid_name (ifname)) - return FALSE; - ifname = ASSERT_VALID_PATH_COMPONENT (ifname); + if (props->group) + NLA_PUT (nlmsg, IFLA_VXLAN_GROUP, sizeof (props->group), &props->group); + else if (memcmp (&props->group6, &in6addr_any, sizeof (in6addr_any))) + NLA_PUT (nlmsg, IFLA_VXLAN_GROUP6, sizeof (props->group6), &props->group6); - path = g_strdup_printf ("/sys/class/net/%s/owner", ifname); - val = nm_platform_sysctl_get (platform, 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; + if (props->local) + NLA_PUT (nlmsg, IFLA_VXLAN_LOCAL, sizeof (props->local), &props->local); + else if (memcmp (&props->local6, &in6addr_any, sizeof (in6addr_any))) + NLA_PUT (nlmsg, IFLA_VXLAN_LOCAL6, sizeof (props->local6), &props->local6); - path = g_strdup_printf ("/sys/class/net/%s/group", ifname); - val = nm_platform_sysctl_get (platform, 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; + if (props->parent_ifindex >= 0) + NLA_PUT_U32 (nlmsg, IFLA_VXLAN_LINK, props->parent_ifindex); - path = g_strdup_printf ("/sys/class/net/%s/tun_flags", ifname); - val = nm_platform_sysctl_get (platform, path); - g_free (path); - if (val) { - gint64 flags; + if (props->src_port_min || props->src_port_max) { + port_range.low = htons (props->src_port_min); + port_range.high = htons (props->src_port_max); + NLA_PUT (nlmsg, IFLA_VXLAN_PORT_RANGE, sizeof (port_range), &port_range); + } - 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 & (IFF_TUN | IFF_TAP)) == IFF_TUN) ? "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; + NLA_PUT_U16 (nlmsg, IFLA_VXLAN_PORT, htons (props->dst_port)); + NLA_PUT_U8 (nlmsg, IFLA_VXLAN_TOS, props->tos); + NLA_PUT_U8 (nlmsg, IFLA_VXLAN_TTL, props->ttl); + NLA_PUT_U32 (nlmsg, IFLA_VXLAN_AGEING, props->ageing); + NLA_PUT_U32 (nlmsg, IFLA_VXLAN_LIMIT, props->limit); + NLA_PUT_U8 (nlmsg, IFLA_VXLAN_LEARNING, !!props->learning); + NLA_PUT_U8 (nlmsg, IFLA_VXLAN_PROXY, !!props->proxy); + NLA_PUT_U8 (nlmsg, IFLA_VXLAN_RSC, !!props->rsc); + NLA_PUT_U8 (nlmsg, IFLA_VXLAN_L2MISS, !!props->l2miss); + NLA_PUT_U8 (nlmsg, IFLA_VXLAN_L3MISS, !!props->l3miss); - return success; -} + nla_nest_end (nlmsg, data); + nla_nest_end (nlmsg, info); -static gboolean -tun_get_properties (NMPlatform *platform, int ifindex, NMPlatformTunProperties *props) -{ - return tun_get_properties_ifname (platform, nm_platform_link_get_name (platform, ifindex), props); + return do_add_link_with_lookup (platform, NM_LINK_TYPE_VXLAN, name, nlmsg, out_link); +nla_put_failure: + g_return_val_if_reached (FALSE); } -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; +static void +_vlan_change_vlan_qos_mapping_create (gboolean is_ingress_map, + gboolean reset_all, + const NMVlanQosMapping *current_map, + guint current_n_map, + const NMVlanQosMapping *set_map, + guint set_n_map, + NMVlanQosMapping **out_map, + guint *out_n_map) +{ + NMVlanQosMapping *map; + guint i, j, len; + const guint INGRESS_RANGE_LEN = 8; + + nm_assert (out_map && !*out_map); + nm_assert (out_n_map && !*out_n_map); + + if (!reset_all) + current_n_map = 0; + else if (is_ingress_map) + current_n_map = INGRESS_RANGE_LEN; + + len = current_n_map + set_n_map; + + if (len == 0) + return; - err = nla_parse_nested (tb, IFLA_MACVLAN_MAX, info_data, - (struct nla_policy *) macvlan_info_policy); - if (err < 0) - return err; + map = g_new (NMVlanQosMapping, len); - 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; + if (current_n_map) { + if (is_ingress_map) { + /* For the ingress-map, there are only 8 entries (0 to 7). + * When the user requests to reset all entires, we don't actually + * need the cached entries, we can just explicitly clear all possible + * ones. + * + * That makes only a real difference in case our cache is out-of-date. + * + * For the egress map we cannot do that, because there are far too + * many. There we can only clear the entries that we know about. */ + for (i = 0; i < INGRESS_RANGE_LEN; i++) { + map[i].from = i; + map[i].to = 0; + } + } else { + for (i = 0; i < current_n_map; i++) { + map[i].from = current_map[i].from; + map[i].to = 0; + } + } + } + if (set_n_map) + memcpy (&map[current_n_map], set_map, sizeof (*set_map) * set_n_map); + + g_qsort_with_data (map, + len, + sizeof (*map), + _vlan_qos_mapping_cmp_from, + NULL); + + for (i = 0, j = 0; i < len; i++) { + if ( ( is_ingress_map && !VLAN_XGRESS_PRIO_VALID (map[i].from)) + || (!is_ingress_map && !VLAN_XGRESS_PRIO_VALID (map[i].to))) + continue; + if ( j > 0 + && map[j - 1].from == map[i].from) + map[j - 1] = map[i]; + else + map[j++] = map[i]; } -#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; + *out_map = map; + *out_n_map = j; } static gboolean -macvlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformMacvlanProperties *props) +link_vlan_change (NMPlatform *platform, + int ifindex, + NMVlanFlags flags_mask, + NMVlanFlags flags_set, + gboolean ingress_reset_all, + const NMVlanQosMapping *ingress_map, + gsize n_ingress_map, + gboolean egress_reset_all, + const NMVlanQosMapping *egress_map, + gsize n_egress_map) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - int err; - const NMPObject *obj; - - obj = cache_lookup_link (platform, ifindex); - if (!obj) + const NMPObject *obj_cache; + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + unsigned flags; + const NMPObjectLnkVlan *lnk; + guint new_n_ingress_map = 0; + guint new_n_egress_map = 0; + gs_free NMVlanQosMapping *new_ingress_map = NULL; + gs_free NMVlanQosMapping *new_egress_map = NULL; + char s_flags[64]; + char s_ingress[256]; + char s_egress[256]; + + obj_cache = nmp_cache_lookup_link (priv->cache, ifindex); + if ( !obj_cache + || !obj_cache->_link.netlink.is_in_netlink) { + _LOGD ("link: change %d: %s: link does not exist", ifindex, "vlan"); return FALSE; - - props->parent_ifindex = obj->link.parent; - - err = _nl_link_parse_info_data (priv->nlh, ifindex, - macvlan_info_data_parser, props); - if (err != 0) { - warning ("(%s) could not read properties: %s", - obj->link.name, 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 -/* older kernel header might not contain 'struct ifla_vxlan_port_range'. - * Redefine it. */ -struct nm_ifla_vxlan_port_range { - guint16 low; - guint16 high; -}; + lnk = obj_cache->_link.netlink.lnk ? &obj_cache->_link.netlink.lnk->_lnk_vlan : NULL; + flags = obj_cache->link.flags; + + flags_set &= flags_mask; + + _vlan_change_vlan_qos_mapping_create (TRUE, + ingress_reset_all, + lnk ? lnk->ingress_qos_map : NULL, + lnk ? lnk->n_ingress_qos_map : 0, + ingress_map, + n_ingress_map, + &new_ingress_map, + &new_n_ingress_map); + + _vlan_change_vlan_qos_mapping_create (FALSE, + egress_reset_all, + lnk ? lnk->egress_qos_map : NULL, + lnk ? lnk->n_egress_qos_map : 0, + egress_map, + n_egress_map, + &new_egress_map, + &new_n_egress_map); + + _LOGD ("link: change %d: vlan:%s%s%s", + ifindex, + flags_mask + ? nm_sprintf_buf (s_flags, " flags 0x%x/0x%x", (unsigned) flags_set, (unsigned) flags_mask) + : "", + new_n_ingress_map + ? nm_platform_vlan_qos_mapping_to_string (" ingress-qos-map", + new_ingress_map, + new_n_ingress_map, + s_ingress, + sizeof (s_ingress)) + : "", + new_n_egress_map + ? nm_platform_vlan_qos_mapping_to_string (" egress-qos-map", + new_egress_map, + new_n_egress_map, + s_egress, + sizeof (s_egress)) + : ""); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + 0, + ifindex, + NULL, + 0, + 0); + if ( !nlmsg + || !_nl_msg_new_link_set_linkinfo_vlan (nlmsg, + -1, + flags_mask, + flags_set, + new_ingress_map, + new_n_ingress_map, + new_egress_map, + new_n_egress_map)) + g_return_val_if_reached (FALSE); -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 nm_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 }, -}; + return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS; +} static int -vxlan_info_data_parser (struct nlattr *info_data, gpointer parser_data) +tun_add (NMPlatform *platform, const char *name, gboolean tap, + gint64 owner, gint64 group, gboolean pi, gboolean vnet_hdr, + gboolean multi_queue, const NMPlatformLink **out_link) { - NMPlatformVxlanProperties *props = parser_data; - struct nlattr *tb[IFLA_VXLAN_MAX + 1]; - struct nm_ifla_vxlan_port_range *range; - int err; + const NMPObject *obj; + struct ifreq ifr = { }; + int fd; - err = nla_parse_nested (tb, IFLA_VXLAN_MAX, info_data, - (struct nla_policy *) vxlan_info_policy); - if (err < 0) - return err; + _LOGD ("link: add %s '%s' owner %" G_GINT64_FORMAT " group %" G_GINT64_FORMAT, + tap ? "tap" : "tun", name, owner, group); - memset (props, 0, sizeof (*props)); + fd = open ("/dev/net/tun", O_RDWR); + if (fd < 0) + return FALSE; - if (tb[IFLA_VXLAN_LINK]) - props->parent_ifindex = nla_get_u32 (tb[IFLA_VXLAN_LINK]); - if (tb[IFLA_VXLAN_ID]) - 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)); + strncpy (ifr.ifr_name, name, IFNAMSIZ); + ifr.ifr_flags = tap ? IFF_TAP : IFF_TUN; - if (tb[IFLA_VXLAN_AGEING]) - props->ageing = nla_get_u32 (tb[IFLA_VXLAN_AGEING]); - if (tb[IFLA_VXLAN_LIMIT]) - props->limit = nla_get_u32 (tb[IFLA_VXLAN_LIMIT]); - if (tb[IFLA_VXLAN_TOS]) - props->tos = nla_get_u8 (tb[IFLA_VXLAN_TOS]); - if (tb[IFLA_VXLAN_TTL]) - props->ttl = nla_get_u8 (tb[IFLA_VXLAN_TTL]); + if (!pi) + ifr.ifr_flags |= IFF_NO_PI; + if (vnet_hdr) + ifr.ifr_flags |= IFF_VNET_HDR; + if (multi_queue) + ifr.ifr_flags |= NM_IFF_MULTI_QUEUE; - if (tb[IFLA_VXLAN_PORT]) - props->dst_port = nla_get_u16 (tb[IFLA_VXLAN_PORT]); + if (ioctl (fd, TUNSETIFF, &ifr)) { + close (fd); + return FALSE; + } - if (tb[IFLA_VXLAN_PORT_RANGE]) { - range = nla_data (tb[IFLA_VXLAN_PORT_RANGE]); - props->src_port_min = range->low; - props->src_port_max = range->high; + if (owner >= 0 && owner < G_MAXINT32) { + if (ioctl (fd, TUNSETOWNER, (uid_t) owner)) { + close (fd); + return FALSE; + } } - if (tb[IFLA_VXLAN_LEARNING]) - props->learning = !!nla_get_u8 (tb[IFLA_VXLAN_LEARNING]); - if (tb[IFLA_VXLAN_PROXY]) - props->proxy = !!nla_get_u8 (tb[IFLA_VXLAN_PROXY]); - if (tb[IFLA_VXLAN_RSC]) - props->rsc = !!nla_get_u8 (tb[IFLA_VXLAN_RSC]); - if (tb[IFLA_VXLAN_L2MISS]) - props->l2miss = !!nla_get_u8 (tb[IFLA_VXLAN_L2MISS]); - if (tb[IFLA_VXLAN_L3MISS]) - props->l3miss = !!nla_get_u8 (tb[IFLA_VXLAN_L3MISS]); + if (group >= 0 && group < G_MAXINT32) { + if (ioctl (fd, TUNSETGROUP, (gid_t) group)) { + close (fd); + return FALSE; + } + } + + if (ioctl (fd, TUNSETPERSIST, 1)) { + close (fd); + return FALSE; + } + do_request_link (platform, 0, name); + obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, + 0, name, FALSE, + tap ? NM_LINK_TYPE_TAP : NM_LINK_TYPE_TUN, + NULL, NULL); + if (out_link) + *out_link = obj ? &obj->link : NULL; + + return !!obj; +} + +static gboolean +link_enslave (NMPlatform *platform, int master, int slave) +{ + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + int ifindex = slave; + + _LOGD ("link: change %d: enslave: master %d", slave, master); + + nlmsg = _nl_msg_new_link (RTM_NEWLINK, + 0, + ifindex, + NULL, + 0, + 0); + if (!nlmsg) + return FALSE; - return 0; + NLA_PUT_U32 (nlmsg, IFLA_MASTER, master); + + return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS; +nla_put_failure: + g_return_val_if_reached (FALSE); } static gboolean -vxlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformVxlanProperties *props) +link_release (NMPlatform *platform, int master, int slave) { - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - int err; + return link_enslave (platform, 0, slave); +} - err = _nl_link_parse_info_data (priv->nlh, ifindex, - vxlan_info_data_parser, props); - if (err != 0) { - warning ("(%s) could not read vxlan properties: %s", - nm_platform_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) +static gboolean +infiniband_partition_add (NMPlatform *platform, int parent, int p_key, const NMPlatformLink **out_link) { - NMPlatformGreProperties *props = parser_data; - struct nlattr *tb[IFLA_GRE_MAX + 1]; - int err; + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + const NMPObject *obj_parent; + const NMPObject *obj; + gs_free char *path = NULL; + gs_free char *id = NULL; + gs_free char *ifname = NULL; - err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, - (struct nla_policy *) gre_info_policy); - if (err < 0) - return err; + obj_parent = nmp_cache_lookup_link (priv->cache, parent); + if (!obj_parent || !obj_parent->link.name[0]) + g_return_val_if_reached (FALSE); - 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]); + ifname = g_strdup_printf ("%s.%04x", obj_parent->link.name, p_key); - return 0; -} + path = g_strdup_printf ("/sys/class/net/%s/create_child", ASSERT_VALID_PATH_COMPONENT (obj_parent->link.name)); + id = g_strdup_printf ("0x%04x", p_key); + if (!nm_platform_sysctl_set (platform, path, id)) + return FALSE; -static gboolean -gre_get_properties (NMPlatform *platform, int ifindex, NMPlatformGreProperties *props) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - int err; + do_request_link (platform, 0, ifname); - err = _nl_link_parse_info_data (priv->nlh, ifindex, - gre_info_data_parser, props); - if (err != 0) { - warning ("(%s) could not read gre properties: %s", - nm_platform_link_get_name (platform, ifindex), nl_geterror (err)); - } - return (err == 0); + obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, + 0, ifname, FALSE, NM_LINK_TYPE_INFINIBAND, NULL, NULL); + if (out_link) + *out_link = obj ? &obj->link : NULL; + return !!obj; } +/******************************************************************/ + static WifiData * wifi_get_wifi_data (NMPlatform *platform, int ifindex) { @@ -3846,16 +4943,6 @@ wifi_get_bssid (NMPlatform *platform, int ifindex, guint8 *bssid) 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) { @@ -3906,6 +4993,15 @@ wifi_set_mode (NMPlatform *platform, int ifindex, NM80211Mode mode) wifi_utils_set_mode (wifi_data, mode); } +static void +wifi_set_powersave (NMPlatform *platform, int ifindex, guint32 powersave) +{ + WifiData *wifi_data = wifi_get_wifi_data (platform, ifindex); + + if (wifi_data) + wifi_utils_set_powersave (wifi_data, powersave); +} + static guint32 wifi_find_frequency (NMPlatform *platform, int ifindex, const guint32 *freqs) { @@ -3926,6 +5022,7 @@ wifi_indicate_addressing_running (NMPlatform *platform, int ifindex, gboolean ru wifi_utils_indicate_addressing_running (wifi_data, running); } +/******************************************************************/ static guint32 mesh_get_channel (NMPlatform *platform, int ifindex) @@ -3960,6 +5057,8 @@ mesh_set_ssid (NMPlatform *platform, int ifindex, const guint8 *ssid, gsize len) return wifi_utils_set_mesh_ssid (wifi_data, ssid, len); } +/******************************************************************/ + static gboolean link_get_wake_on_lan (NMPlatform *platform, int ifindex) { @@ -4019,208 +5118,124 @@ ip6_address_get_all (NMPlatform *platform, int ifindex) return ipx_address_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ADDRESS); } -#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 (NMPlatform *platform, - int family, - int ifindex, - gconstpointer addr, - gconstpointer peer_addr, - int plen, - guint32 lifetime, - guint32 preferred, - guint flags, - const char *label) -{ - auto_nl_object struct rtnl_addr *rtnladdr = _nl_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 = _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, RT_SCOPE_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 = _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 = _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; - } - } - - _nl_rtnl_addr_set_prefixlen (rtnladdr, plen); - if ( (lifetime != 0 && lifetime != NM_PLATFORM_LIFETIME_PERMANENT) - || (preferred != 0 && preferred != NM_PLATFORM_LIFETIME_PERMANENT)) { - /* note that here we set the relative timestamps (ticking from *now*). */ - rtnl_addr_set_valid_lifetime (rtnladdr, lifetime); - rtnl_addr_set_preferred_lifetime (rtnladdr, preferred); - } - if (flags) { - if ((flags & ~0xFF) && !_support_kernel_extended_ifa_flags_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; -} - -struct nl_object * -_nmp_vt_cmd_plobj_to_nl_ip4_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only) -{ - const NMPlatformIP4Address *obj = (const NMPlatformIP4Address *) _obj; - guint32 lifetime, preferred; - - nmp_utils_lifetime_get (obj->timestamp, obj->lifetime, obj->preferred, - 0, 0, &lifetime, &preferred); - - return build_rtnl_addr (platform, - AF_INET, - obj->ifindex, - &obj->address, - obj->peer_address ? &obj->peer_address : NULL, - obj->plen, - lifetime, - preferred, - 0, - obj->label[0] ? obj->label : NULL); -} - -struct nl_object * -_nmp_vt_cmd_plobj_to_nl_ip6_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only) -{ - const NMPlatformIP6Address *obj = (const NMPlatformIP6Address *) _obj; - guint32 lifetime, preferred; - - nmp_utils_lifetime_get (obj->timestamp, obj->lifetime, obj->preferred, - 0, 0, &lifetime, &preferred); - - return build_rtnl_addr (platform, - AF_INET6, - obj->ifindex, - &obj->address, - !IN6_IS_ADDR_UNSPECIFIED (&obj->peer_address) ? &obj->peer_address : NULL, - obj->plen, - lifetime, - preferred, - 0, - NULL); -} - static gboolean ip4_address_add (NMPlatform *platform, int ifindex, in_addr_t addr, - in_addr_t peer_addr, int plen, + in_addr_t peer_addr, guint32 lifetime, guint32 preferred, const char *label) { - NMPObject obj_needle; - auto_nl_object struct nl_object *nlo = NULL; + NMPObject obj_id; + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + + nlmsg = _nl_msg_new_address (RTM_NEWADDR, + NLM_F_CREATE | NLM_F_REPLACE, + AF_INET, + ifindex, + &addr, + plen, + &peer_addr, + 0, + ip4_address_is_link_local (addr) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE, + lifetime, + preferred, + label); - nlo = build_rtnl_addr (platform, AF_INET, ifindex, &addr, - peer_addr ? &peer_addr : NULL, - plen, lifetime, preferred, 0, - label); - return do_add_addrroute (platform, - nmp_object_stackinit_id_ip4_address (&obj_needle, ifindex, addr, plen), - nlo); + nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_addr); + return do_add_addrroute (platform, &obj_id, nlmsg); } static gboolean ip6_address_add (NMPlatform *platform, int ifindex, struct in6_addr addr, - struct in6_addr peer_addr, int plen, + struct in6_addr peer_addr, guint32 lifetime, guint32 preferred, guint flags) { - NMPObject obj_needle; - auto_nl_object struct nl_object *nlo = NULL; + NMPObject obj_id; + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - nlo = build_rtnl_addr (platform, AF_INET6, ifindex, &addr, - IN6_IS_ADDR_UNSPECIFIED (&peer_addr) ? NULL : &peer_addr, - plen, lifetime, preferred, flags, - NULL); - return do_add_addrroute (platform, - nmp_object_stackinit_id_ip6_address (&obj_needle, ifindex, &addr, plen), - nlo); + nlmsg = _nl_msg_new_address (RTM_NEWADDR, + NLM_F_CREATE | NLM_F_REPLACE, + AF_INET6, + ifindex, + &addr, + plen, + &peer_addr, + flags, + RT_SCOPE_UNIVERSE, + lifetime, + preferred, + NULL); + + nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr, plen); + return do_add_addrroute (platform, &obj_id, nlmsg); } static gboolean ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in_addr_t peer_address) { - NMPObject obj_needle; + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + NMPObject obj_id; + + nlmsg = _nl_msg_new_address (RTM_DELADDR, + 0, + AF_INET, + ifindex, + &addr, + plen, + &peer_address, + 0, + RT_SCOPE_NOWHERE, + NM_PLATFORM_LIFETIME_PERMANENT, + NM_PLATFORM_LIFETIME_PERMANENT, + NULL); + if (!nlmsg) + g_return_val_if_reached (FALSE); - nmp_object_stackinit_id_ip4_address (&obj_needle, ifindex, addr, plen); - obj_needle.ip4_address.peer_address = peer_address; - return do_delete_object (platform, &obj_needle, NULL); + nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_address); + return do_delete_object (platform, &obj_id, nlmsg); } static gboolean ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen) { - NMPObject obj_needle; + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + NMPObject obj_id; + + nlmsg = _nl_msg_new_address (RTM_DELADDR, + 0, + AF_INET6, + ifindex, + &addr, + plen, + NULL, + 0, + RT_SCOPE_NOWHERE, + NM_PLATFORM_LIFETIME_PERMANENT, + NM_PLATFORM_LIFETIME_PERMANENT, + NULL); + if (!nlmsg) + g_return_val_if_reached (FALSE); - nmp_object_stackinit_id_ip6_address (&obj_needle, ifindex, &addr, plen); - return do_delete_object (platform, &obj_needle, NULL); + nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr, plen); + return do_delete_object (platform, &obj_id, nlmsg); } static const NMPlatformIP4Address * -ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen) +ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in_addr_t peer_address) { - NMPObject obj_needle; + NMPObject obj_id; const NMPObject *obj; - nmp_object_stackinit_id_ip4_address (&obj_needle, ifindex, addr, plen); - obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_needle); + nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_address); + obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id); if (nmp_object_is_visible (obj)) return &obj->ip4_address; return NULL; @@ -4229,11 +5244,11 @@ ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen) static const NMPlatformIP6Address * ip6_address_get (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen) { - NMPObject obj_needle; + NMPObject obj_id; const NMPObject *obj; - nmp_object_stackinit_id_ip6_address (&obj_needle, ifindex, &addr, plen); - obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_needle); + nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr, plen); + obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id); if (nmp_object_is_visible (obj)) return &obj->ip6_address; return NULL; @@ -4292,113 +5307,29 @@ ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags fl return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ROUTE, flags); } -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, NMIPConfigSource source, - gconstpointer network, int plen, gconstpointer gateway, - gconstpointer pref_src, - guint32 metric, guint32 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 ? _nl_addr_build (family, gateway, addrlen) : NULL; - auto_nl_addr struct nl_addr *pref_src_nl = pref_src ? _nl_addr_build (family, pref_src, 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 = _nl_addr_build (family, network_clean, plen ? addrlen : 0); - nl_addr_set_prefixlen (dst, plen); - - rtnlroute = _nl_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, _nm_ip_config_source_to_rtprot (source)); - - nexthop = _nl_rtnl_route_nh_alloc (); - rtnl_route_nh_set_ifindex (nexthop, ifindex); - if (gw && !nl_addr_iszero (gw)) - rtnl_route_nh_set_gateway (nexthop, gw); - if (pref_src_nl) - rtnl_route_set_pref_src (rtnlroute, pref_src_nl); - rtnl_route_add_nexthop (rtnlroute, nexthop); - - if (mss > 0) - rtnl_route_set_metric (rtnlroute, RTAX_ADVMSS, mss); - - return (struct nl_object *) rtnlroute; -} - -struct nl_object * -_nmp_vt_cmd_plobj_to_nl_ip4_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only) -{ - const NMPlatformIP4Route *obj = (const NMPlatformIP4Route *) _obj; - - return build_rtnl_route (AF_INET, - obj->ifindex, - obj->source, - &obj->network, - obj->plen, - &obj->gateway, - obj->pref_src ? &obj->pref_src : NULL, - obj->metric, - obj->mss); -} - -struct nl_object * -_nmp_vt_cmd_plobj_to_nl_ip6_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only) -{ - const NMPlatformIP6Route *obj = (const NMPlatformIP6Route *) _obj; - - return build_rtnl_route (AF_INET6, - obj->ifindex, - obj->source, - &obj->network, - obj->plen, - &obj->gateway, - NULL, - obj->metric, - obj->mss); -} - static gboolean ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, in_addr_t network, int plen, in_addr_t gateway, - guint32 pref_src, guint32 metric, guint32 mss) + in_addr_t pref_src, guint32 metric, guint32 mss) { - NMPObject obj_needle; - auto_nl_object struct nl_object *nlo = NULL; + NMPObject obj_id; + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + + nlmsg = _nl_msg_new_route (RTM_NEWROUTE, + NLM_F_CREATE | NLM_F_REPLACE, + AF_INET, + ifindex, + source, + gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK, + &network, + plen, + &gateway, + metric, + mss, + pref_src ? &pref_src : NULL); - nlo = build_rtnl_route (AF_INET, ifindex, source, &network, plen, &gateway, pref_src ? &pref_src : NULL, metric, mss); - return do_add_addrroute (platform, - nmp_object_stackinit_id_ip4_route (&obj_needle, ifindex, network, plen, metric), - nlo); + nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric); + return do_add_addrroute (platform, &obj_id, nlmsg); } static gboolean @@ -4406,30 +5337,34 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source, struct in6_addr network, int plen, struct in6_addr gateway, guint32 metric, guint32 mss) { - NMPObject obj_needle; - auto_nl_object struct nl_object *nlo = NULL; + NMPObject obj_id; + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - metric = nm_utils_ip6_route_metric_normalize (metric); + nlmsg = _nl_msg_new_route (RTM_NEWROUTE, + NLM_F_CREATE | NLM_F_REPLACE, + AF_INET6, + ifindex, + source, + !IN6_IS_ADDR_UNSPECIFIED (&gateway) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK, + &network, + plen, + &gateway, + metric, + mss, + NULL); - nlo = build_rtnl_route (AF_INET6, ifindex, source, &network, plen, &gateway, NULL, metric, mss); - return do_add_addrroute (platform, - nmp_object_stackinit_id_ip6_route (&obj_needle, ifindex, &network, plen, metric), - nlo); + nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric); + return do_add_addrroute (platform, &obj_id, nlmsg); } static gboolean ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen, guint32 metric) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - in_addr_t gateway = 0; - auto_nl_object struct nl_object *nlo = build_rtnl_route (AF_INET, ifindex, NM_IP_CONFIG_SOURCE_UNKNOWN, &network, plen, &gateway, NULL, metric, 0); - uint8_t scope = RT_SCOPE_NOWHERE; - const NMPObject *obj; - NMPObject obj_needle; + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + NMPObject obj_id; - g_return_val_if_fail (nlo, FALSE); - - nmp_object_stackinit_id_ip4_route (&obj_needle, ifindex, network, plen, metric); + nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric); if (metric == 0) { /* Deleting an IPv4 route with metric 0 does not only delete an exectly matching route. @@ -4439,94 +5374,81 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen * Instead, make sure that we have the most recent state and process all * delayed actions (including re-reading data from netlink). */ delayed_action_handle_all (platform, TRUE); - } - - obj = nmp_cache_lookup_obj (priv->cache, &obj_needle); - - if (metric == 0 && !obj) { - /* hmm... we are about to delete an IP4 route with metric 0. We must only - * send the delete request if such a route really exists. Above we refreshed - * the platform cache, still no such route exists. - * - * Be extra careful and reload the routes. We must be sure that such a - * route doesn't exists, because when we add an IPv4 address, we immediately - * afterwards try to delete the kernel-added device route with metric 0. - * It might be, that we didn't yet get the notification about that route. - * - * FIXME: once our ip4_address_add() is sure that upon return we have - * the latest state from in the platform cache, we might save this - * additional expensive cache-resync. */ - do_request_one_type (platform, NMP_OBJECT_TYPE_IP4_ROUTE, TRUE); - - obj = nmp_cache_lookup_obj (priv->cache, &obj_needle); - if (!obj) - return TRUE; - } - - 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 (obj) - scope = nm_platform_route_scope_inv (obj->ip4_route.scope_inv); + if (!nmp_cache_lookup_obj (priv->cache, &obj_id)) { + /* hmm... we are about to delete an IP4 route with metric 0. We must only + * send the delete request if such a route really exists. Above we refreshed + * the platform cache, still no such route exists. + * + * Be extra careful and reload the routes. We must be sure that such a + * route doesn't exists, because when we add an IPv4 address, we immediately + * afterwards try to delete the kernel-added device route with metric 0. + * It might be, that we didn't yet get the notification about that route. + * + * FIXME: once our ip4_address_add() is sure that upon return we have + * the latest state from in the platform cache, we might save this + * additional expensive cache-resync. */ + do_request_one_type (platform, NMP_OBJECT_TYPE_IP4_ROUTE); - 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; + if (!nmp_cache_lookup_obj (priv->cache, &obj_id)) + return TRUE; } } - rtnl_route_set_scope ((struct rtnl_route *) nlo, scope); - - /* we only support routes with TOS zero. As such, delete_route() is also only able to delete - * routes with tos==0. build_rtnl_route() already initializes tos properly. */ - /* 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 - */ + nlmsg = _nl_msg_new_route (RTM_DELROUTE, + 0, + AF_INET, + ifindex, + NM_IP_CONFIG_SOURCE_UNKNOWN, + RT_SCOPE_NOWHERE, + &network, + plen, + NULL, + metric, + 0, + NULL); + if (!nlmsg) + return FALSE; - return do_delete_object (platform, &obj_needle, nlo); + return do_delete_object (platform, &obj_id, nlmsg); } static gboolean ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, guint32 metric) { - struct in6_addr gateway = IN6ADDR_ANY_INIT; - auto_nl_object struct nl_object *nlo = NULL; - NMPObject obj_needle; + nm_auto_nlmsg struct nl_msg *nlmsg = NULL; + NMPObject obj_id; metric = nm_utils_ip6_route_metric_normalize (metric); - nlo = build_rtnl_route (AF_INET6, ifindex, NM_IP_CONFIG_SOURCE_UNKNOWN ,&network, plen, &gateway, NULL, metric, 0); + nlmsg = _nl_msg_new_route (RTM_DELROUTE, + 0, + AF_INET6, + ifindex, + NM_IP_CONFIG_SOURCE_UNKNOWN, + RT_SCOPE_NOWHERE, + &network, + plen, + NULL, + metric, + 0, + NULL); + if (!nlmsg) + return FALSE; - nmp_object_stackinit_id_ip6_route (&obj_needle, ifindex, &network, plen, metric); + nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric); - return do_delete_object (platform, &obj_needle, nlo); + return do_delete_object (platform, &obj_id, nlmsg); } static const NMPlatformIP4Route * ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, int plen, guint32 metric) { - NMPObject obj_needle; + NMPObject obj_id; const NMPObject *obj; - nmp_object_stackinit_id_ip4_route (&obj_needle, ifindex, network, plen, metric); - obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_needle); + nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric); + obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id); if (nmp_object_is_visible (obj)) return &obj->ip4_route; return NULL; @@ -4535,13 +5457,13 @@ ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, int plen, g static const NMPlatformIP6Route * ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, guint32 metric) { - NMPObject obj_needle; + NMPObject obj_id; const NMPObject *obj; metric = nm_utils_ip6_route_metric_normalize (metric); - nmp_object_stackinit_id_ip6_route (&obj_needle, ifindex, &network, plen, metric); - obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_needle); + nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric); + obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id); if (nmp_object_is_visible (obj)) return &obj->ip6_route; return NULL; @@ -4553,22 +5475,6 @@ ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, int p #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) { - if (creds) - warning ("netlink: received non-kernel message (pid %d)", creds->pid); - else - warning ("netlink: received message without credentials"); - return NL_STOP; - } - - return NL_OK; -} - static gboolean event_handler (GIOChannel *channel, GIOCondition io_condition, @@ -4578,148 +5484,288 @@ event_handler (GIOChannel *channel, return TRUE; } -static gboolean -event_handler_read_netlink_one (NMPlatform *platform) +/*****************************************************************************/ + +/* copied from libnl3's recvmsgs() */ +static int +event_handler_recvmsgs (NMPlatform *platform, gboolean handle_events) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - int nle; + struct nl_sock *sk = priv->nlh; + int n, err = 0, multipart = 0, interrupted = 0, nrecv = 0; + unsigned char *buf = NULL; + struct nlmsghdr *hdr; + WaitForNlResponseResult seq_result; + + /* + nla is passed on to not only to nl_recv() but may also be passed + to a function pointer provided by the caller which may or may not + initialize the variable. Thomas Graf. + */ + struct sockaddr_nl nla = {0}; + struct nl_msg *msg = NULL; + struct ucred *creds = NULL; +continue_reading: errno = 0; - nle = nl_recvmsgs_default (priv->nlh_event); + n = nl_recv (sk, &nla, &buf, &creds); /* Work around a libnl bug fixed in 3.2.22 (375a6294) */ - if (nle == 0 && errno == EAGAIN) { + if (n == 0 && errno == EAGAIN) { /* EAGAIN is equal to EWOULDBLOCK. If it would not be, we'd have to * workaround libnl3 mapping EWOULDBLOCK to -NLE_FAILURE. */ G_STATIC_ASSERT (EAGAIN == EWOULDBLOCK); - nle = -NLE_AGAIN; + n = -NLE_AGAIN; } - if (nle < 0) - switch (nle) { - case -NLE_AGAIN: - return FALSE; - case -NLE_DUMP_INTR: - debug ("Uncritical failure to retrieve incoming events: %s (%d)", nl_geterror (nle), nle); - break; - case -NLE_NOMEM: - info ("Too many netlink events. Need to resynchronize platform cache"); - /* Drain the event queue, we've lost events and are out of sync anyway and we'd - * like to free up some space. We'll read in the status synchronously. */ - _nl_sock_flush_data (priv->nlh_event); - priv->nlh_seq_expect = 0; - delayed_action_schedule (platform, - DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | - DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, - NULL); - break; - default: - error ("Failed to retrieve incoming events: %s (%d)", nl_geterror (nle), nle); - break; + if (n <= 0) + return n; + + if (!handle_events) { + /* we read until failure or there is nothing to read (EAGAIN). */ + goto continue_reading; } - return TRUE; + + hdr = (struct nlmsghdr *) buf; + while (nlmsg_ok (hdr, n)) { + gboolean abort_parsing = FALSE; + + nlmsg_free (msg); + msg = nlmsg_convert (hdr); + if (!msg) { + err = -NLE_NOMEM; + goto out; + } + + nlmsg_set_proto (msg, NETLINK_ROUTE); + nlmsg_set_src (msg, &nla); + nrecv++; + + if (!creds || creds->pid) { + if (creds) + _LOGD ("netlink: recvmsg: received non-kernel message (pid %d)", creds->pid); + else + _LOGD ("netlink: recvmsg: received message without credentials"); + goto stop; + } + + _LOGt ("netlink: recvmsg: new message type %d, seq %u", + hdr->nlmsg_type, hdr->nlmsg_seq); + + if (creds) + nlmsg_set_creds (msg, creds); + + if (hdr->nlmsg_flags & NLM_F_MULTI) + multipart = 1; + + if (hdr->nlmsg_flags & NLM_F_DUMP_INTR) { + /* + * We have to continue reading to clear + * all messages until a NLMSG_DONE is + * received and report the inconsistency. + */ + interrupted = 1; + } + + /* Other side wishes to see an ack for this message */ + if (hdr->nlmsg_flags & NLM_F_ACK) { + /* FIXME: implement */ + } + + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN; + + if (hdr->nlmsg_type == NLMSG_DONE) { + /* messages terminates a multipart message, this is + * usually the end of a message and therefore we slip + * out of the loop by default. the user may overrule + * this action by skipping this packet. */ + multipart = 0; + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; + } else if (hdr->nlmsg_type == NLMSG_NOOP) { + /* Message to be ignored, the default action is to + * skip this message if no callback is specified. The + * user may overrule this action by returning + * NL_PROCEED. */ + } else if (hdr->nlmsg_type == NLMSG_OVERRUN) { + /* Data got lost, report back to user. The default action is to + * quit parsing. The user may overrule this action by retuning + * NL_SKIP or NL_PROCEED (dangerous) */ + err = -NLE_MSG_OVERFLOW; + abort_parsing = TRUE; + } else if (hdr->nlmsg_type == NLMSG_ERROR) { + /* Message carries a nlmsgerr */ + struct nlmsgerr *e = nlmsg_data (hdr); + + if (hdr->nlmsg_len < nlmsg_size (sizeof (*e))) { + /* Truncated error message, the default action + * is to stop parsing. The user may overrule + * this action by returning NL_SKIP or + * NL_PROCEED (dangerous) */ + err = -NLE_MSG_TRUNC; + abort_parsing = TRUE; + } else if (e->error) { + int errsv = e->error > 0 ? e->error : -e->error; + + /* Error message reported back from kernel. */ + _LOGD ("netlink: recvmsg: error message from kernel: %s (%d) for request %d", + strerror (errsv), + errsv, + nlmsg_hdr (msg)->nlmsg_seq); + seq_result = -errsv; + } else + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; + } else { + /* Valid message (not checking for MULTIPART bit to + * get along with broken kernels. NL_SKIP has no + * effect on this. */ + event_valid_msg (platform, msg); + seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK; + } + + event_seq_check (platform, msg, seq_result); + err = 0; + hdr = nlmsg_next (hdr, &n); + + if (abort_parsing) + goto out; + } + + nlmsg_free (msg); + free (buf); + free (creds); + buf = NULL; + msg = NULL; + creds = NULL; + + if (multipart) { + /* Multipart message not yet complete, continue reading */ + goto continue_reading; + } +stop: + err = 0; +out: + nlmsg_free (msg); + free (buf); + free (creds); + + if (interrupted) + err = -NLE_DUMP_INTR; + + if (!err) + err = nrecv; + + return err; } +/*****************************************************************************/ + static gboolean -event_handler_read_netlink_all (NMPlatform *platform, gboolean wait_for_acks) +event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - int r; + int r, nle; struct pollfd pfd; gboolean any = FALSE; - gint64 timestamp = 0, now; - const int TIMEOUT = 250; - int timeout = 0; - guint32 wait_for_seq = 0; + gint64 now_ns; + int timeout_ms; + guint i; + struct { + guint32 seq_number; + gint64 timeout_abs_ns; + } data_next; while (TRUE) { - while (event_handler_read_netlink_one (platform)) + + while (TRUE) { + + nle = event_handler_recvmsgs (platform, TRUE); + + if (nle < 0) + switch (nle) { + case -NLE_AGAIN: + goto after_read; + case -NLE_DUMP_INTR: + _LOGD ("netlink: read: uncritical failure to retrieve incoming events: %s (%d)", nl_geterror (nle), nle); + break; + case -NLE_NOMEM: + _LOGI ("netlink: read: too many netlink events. Need to resynchronize platform cache"); + /* Drain the event queue, we've lost events and are out of sync anyway and we'd + * like to free up some space. We'll read in the status synchronously. */ + delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC); + event_handler_recvmsgs (platform, FALSE); + delayed_action_schedule (platform, + DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS | + DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ADDRESSES | + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ADDRESSES | + DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES | + DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES, + NULL); + break; + default: + _LOGE ("netlink: read: failed to retrieve incoming events: %s (%d)", nl_geterror (nle), nle); + break; + } any = TRUE; + } - if (!wait_for_acks || priv->nlh_seq_expect == 0) { - if (wait_for_seq) - _LOGt ("read-netlink-all: ACK for sequence number %u received", priv->nlh_seq_expect); +after_read: + + if (!NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) return any; - } - now = nm_utils_get_monotonic_timestamp_ms (); - if (wait_for_seq != priv->nlh_seq_expect) { - /* We are waiting for a new sequence number (or we will wait for the first time). - * Reset/start counting the overall wait time. */ - _LOGt ("read-netlink-all: wait for ACK for sequence number %u...", priv->nlh_seq_expect); - wait_for_seq = priv->nlh_seq_expect; - timestamp = now; - timeout = TIMEOUT; - } else { - if ((now - timestamp) >= TIMEOUT) { - /* timeout. Don't wait for this sequence number anymore. */ - break; - } + now_ns = 0; + data_next.seq_number = 0; + data_next.timeout_abs_ns = 0; + + for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; ) { + DelayedActionWaitForNlResponseData *data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i); - /* readjust the wait-time. */ - timeout = TIMEOUT - (now - timestamp); + if (data->seq_result) + delayed_action_wait_for_nl_response_complete (platform, i, data->seq_result); + else if ((now_ns ?: (now_ns = nm_utils_get_monotonic_timestamp_ns ())) > data->timeout_abs_ns) + delayed_action_wait_for_nl_response_complete (platform, i, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_TIMEOUT); + else { + i++; + + if ( data_next.seq_number == 0 + || data_next.timeout_abs_ns > data->timeout_abs_ns) + data_next.seq_number = data->seq_number; + data_next.timeout_abs_ns = data->timeout_abs_ns; + } } + if ( !wait_for_acks + || !NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) + return any; + + nm_assert (data_next.seq_number); + nm_assert (data_next.timeout_abs_ns > 0); + nm_assert (now_ns > 0); + + _LOGT ("netlink: read: wait for ACK for sequence number %u...", data_next.seq_number); + + timeout_ms = (data_next.timeout_abs_ns - now_ns) / (NM_UTILS_NS_PER_SECOND / 1000); + memset (&pfd, 0, sizeof (pfd)); - pfd.fd = nl_socket_get_fd (priv->nlh_event); + pfd.fd = nl_socket_get_fd (priv->nlh); pfd.events = POLLIN; - r = poll (&pfd, 1, timeout); + r = poll (&pfd, 1, MAX (1, timeout_ms)); if (r == 0) { - /* timeout. */ - break; + /* timeout and there is nothing to read. */ + goto after_read; } if (r < 0) { int errsv = errno; if (errsv != EINTR) { - _LOGE ("read-netlink-all: poll failed with %s", strerror (errsv)); + _LOGE ("netlink: read: poll failed with %s", strerror (errsv)); + delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_POLL); return any; } /* Continue to read again, even if there might be nothing to read after EINTR. */ } } - - _LOGW ("read-netlink-all: timeout waiting for ACK to sequence number %u...", wait_for_seq); - priv->nlh_seq_expect = 0; - return any; -} - -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_modify_cb (sock, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, event_seq_check, user_data); - nl_socket_modify_err_cb (sock, NL_CB_CUSTOM, event_err, user_data); - } - - nle = nl_connect (sock, NETLINK_ROUTE); - g_assert (!nle); - nle = nl_socket_set_passcred (sock, 1); - g_assert (!nle); - - /* No blocking for event socket, so that we can drain it safely. */ - if (event) { - nle = nl_socket_set_nonblocking (sock); - g_assert (!nle); - } - - return sock; } /******************************************************************/ @@ -4728,12 +5774,12 @@ static void cache_update_link_udev (NMPlatform *platform, int ifindex, GUdevDevice *udev_device) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - auto_nmp_obj NMPObject *obj_cache = NULL; + nm_auto_nmpobj NMPObject *obj_cache = NULL; gboolean was_visible; NMPCacheOpsType cache_op; cache_op = nmp_cache_update_link_udev (priv->cache, ifindex, udev_device, &obj_cache, &was_visible, cache_pre_hook, platform); - do_emit_signal (platform, obj_cache, cache_op, was_visible, NM_PLATFORM_REASON_INTERNAL); + do_emit_signal (platform, obj_cache, cache_op, was_visible); } static void @@ -4745,23 +5791,23 @@ udev_device_added (NMPlatform *platform, ifname = g_udev_device_get_name (udev_device); if (!ifname) { - debug ("udev-add: failed to get device's interface"); + _LOGD ("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); + _LOGW ("(%s): udev-add: failed to get device's ifindex", ifname); return; } if (ifindex <= 0) { - warning ("(%s): udev-add: retrieved invalid IFINDEX=%d", ifname, ifindex); + _LOGW ("(%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); + _LOGD ("(%s): udev-add: couldn't determine device path; ignoring...", ifname); return; } @@ -4791,7 +5837,7 @@ udev_device_removed (NMPlatform *platform, ifindex = obj->link.ifindex; } - debug ("udev-remove: IFINDEX=%d", ifindex); + _LOGD ("udev-remove: IFINDEX=%d", ifindex); if (ifindex <= 0) return; @@ -4817,9 +5863,9 @@ handle_udev_event (GUdevClient *client, 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); + _LOGD ("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); @@ -4836,9 +5882,11 @@ nm_linux_platform_init (NMLinuxPlatform *self) self->priv = priv; + priv->nlh_seq_next = 1; priv->cache = nmp_cache_new (); priv->delayed_action.list_master_connected = g_ptr_array_new (); priv->delayed_action.list_refresh_link = g_ptr_array_new (); + priv->delayed_action.list_wait_for_nl_response = g_array_new (FALSE, TRUE, sizeof (DelayedActionWaitForNlResponseData)); priv->wifi_data = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) wifi_utils_deinit); } @@ -4856,29 +5904,37 @@ constructed (GObject *_object) _LOGD ("create"); - /* Initialize netlink socket for requests */ - priv->nlh = setup_socket (FALSE, platform); + priv->nlh = nl_socket_alloc (); g_assert (priv->nlh); - debug ("Netlink socket for requests established: port=%u, fd=%d", nl_socket_get_local_port (priv->nlh), nl_socket_get_fd (priv->nlh)); - /* Initialize netlink socket for events */ - priv->nlh_event = setup_socket (TRUE, platform); - g_assert (priv->nlh_event); + nle = nl_connect (priv->nlh, NETLINK_ROUTE); + g_assert (!nle); + nle = nl_socket_set_passcred (priv->nlh, 1); + g_assert (!nle); + + /* No blocking for event socket, so that we can drain it safely. */ + nle = nl_socket_set_nonblocking (priv->nlh); + g_assert (!nle); + /* 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. + * + * FIXME: it's unclear that this is still actually needed. The testsuite + * certainly doesn't fail for me. Maybe it can be removed. */ - nle = nl_socket_set_buffer_size (priv->nlh_event, 131072, 0); + nle = nl_socket_set_buffer_size (priv->nlh, 131072, 0); g_assert (!nle); - nle = nl_socket_add_memberships (priv->nlh_event, + + nle = nl_socket_add_memberships (priv->nlh, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR, RTNLGRP_IPV4_ROUTE, RTNLGRP_IPV6_ROUTE, 0); g_assert (!nle); - debug ("Netlink socket for events established: port=%u, fd=%d", nl_socket_get_local_port (priv->nlh_event), nl_socket_get_fd (priv->nlh_event)); + _LOGD ("Netlink socket for events established: port=%u, fd=%d", nl_socket_get_local_port (priv->nlh), nl_socket_get_fd (priv->nlh)); - priv->event_channel = g_io_channel_unix_new (nl_socket_get_fd (priv->nlh_event)); + priv->event_channel = g_io_channel_unix_new (nl_socket_get_fd (priv->nlh)); g_io_channel_set_encoding (priv->event_channel, NULL, NULL); g_io_channel_set_close_on_unref (priv->event_channel, TRUE); @@ -4931,12 +5987,12 @@ dispose (GObject *object) _LOGD ("dispose"); + delayed_action_wait_for_nl_response_complete_all (platform, WAIT_FOR_NL_RESPONSE_RESULT_FAILED_DISPOSING); + priv->delayed_action.flags = DELAYED_ACTION_TYPE_NONE; g_ptr_array_set_size (priv->delayed_action.list_master_connected, 0); g_ptr_array_set_size (priv->delayed_action.list_refresh_link, 0); - nm_clear_g_source (&priv->delayed_action.idle_id); - g_clear_pointer (&priv->prune_candidates, g_hash_table_unref); G_OBJECT_CLASS (nm_linux_platform_parent_class)->dispose (object); @@ -4951,16 +6007,21 @@ nm_linux_platform_finalize (GObject *object) g_ptr_array_unref (priv->delayed_action.list_master_connected); g_ptr_array_unref (priv->delayed_action.list_refresh_link); + g_array_unref (priv->delayed_action.list_wait_for_nl_response); /* 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); g_object_unref (priv->udev_client); g_hash_table_unref (priv->wifi_data); + if (priv->sysctl_get_prev_values) { + sysctl_clear_cache_list = g_slist_remove (sysctl_clear_cache_list, object); + g_hash_table_destroy (priv->sysctl_get_prev_values); + } + G_OBJECT_CLASS (nm_linux_platform_parent_class)->finalize (object); } @@ -4991,6 +6052,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_get_type_name = link_get_type_name; platform_class->link_get_unmanaged = link_get_unmanaged; + platform_class->link_get_lnk = link_get_lnk; + platform_class->link_refresh = link_refresh; platform_class->link_set_up = link_set_up; @@ -5017,33 +6080,23 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_enslave = link_enslave; platform_class->link_release = link_release; - 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->link_vlan_change = link_vlan_change; + platform_class->link_vxlan_add = link_vxlan_add; - platform_class->infiniband_partition_add = infiniband_partition_add; - platform_class->infiniband_get_info = infiniband_get_info; + platform_class->tun_add = tun_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->infiniband_partition_add = infiniband_partition_add; 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_set_powersave = wifi_set_powersave; platform_class->wifi_find_frequency = wifi_find_frequency; platform_class->wifi_indicate_addressing_running = wifi_indicate_addressing_running; @@ -5051,6 +6104,12 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->mesh_set_channel = mesh_set_channel; platform_class->mesh_set_ssid = mesh_set_ssid; + platform_class->link_gre_add = link_gre_add; + platform_class->link_ip6tnl_add = link_ip6tnl_add; + platform_class->link_macvlan_add = link_macvlan_add; + platform_class->link_ipip_add = link_ipip_add; + platform_class->link_sit_add = link_sit_add; + platform_class->ip4_address_get = ip4_address_get; platform_class->ip6_address_get = ip6_address_get; platform_class->ip4_address_get_all = ip4_address_get_all; diff --git a/src/platform/nm-linux-platform.h b/src/platform/nm-linux-platform.h index a9e2cd82..81f9c738 100644 --- a/src/platform/nm-linux-platform.h +++ b/src/platform/nm-linux-platform.h @@ -50,4 +50,6 @@ GType nm_linux_platform_get_type (void); void nm_linux_platform_setup (void); +void _nm_linux_platform_sysctl_clear_cache (void); + #endif /* __NETWORKMANAGER_LINUX_PLATFORM_H__ */ diff --git a/src/platform/nm-platform-utils.c b/src/platform/nm-platform-utils.c index e9b8d4be..953ac8c5 100644 --- a/src/platform/nm-platform-utils.c +++ b/src/platform/nm-platform-utils.c @@ -29,10 +29,9 @@ #include #include -#include "gsystem-local-alloc.h" #include "nm-utils.h" #include "NetworkManagerUtils.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-setting-wired.h" diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 9948ac8b..3bb44e1a 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -28,20 +28,27 @@ #include #include #include +#include +#include +#include -#include "gsystem-local-alloc.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" #include "nm-platform.h" #include "nm-platform-utils.h" +#include "nmp-object.h" #include "NetworkManagerUtils.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-enum-types.h" #include "nm-core-internal.h" #define ADDRESS_LIFETIME_PADDING 5 G_STATIC_ASSERT (sizeof ( ((NMPlatformLink *) NULL)->addr.data ) == NM_UTILS_HWADDR_LEN_MAX); +G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPAddress, address_ptr) == G_STRUCT_OFFSET (NMPlatformIP4Address, address)); +G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPAddress, address_ptr) == G_STRUCT_OFFSET (NMPlatformIP6Address, address)); +G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OFFSET (NMPlatformIP4Route, network)); +G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OFFSET (NMPlatformIP6Route, network)); #define _NMLOG_DOMAIN LOGD_PLATFORM #define _NMLOG_PREFIX_NAME "platform" @@ -64,21 +71,15 @@ G_STATIC_ASSERT (sizeof ( ((NMPlatformLink *) NULL)->addr.data ) == NM_UTILS_HWA } \ } G_STMT_END +#define LOG_FMT_IP_TUNNEL "adding %s '%s' parent %u local %s remote %s" + +/*****************************************************************************/ + #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 }; +static guint signals[_NM_PLATFORM_SIGNAL_ID_LAST] = { 0 }; enum { PROP_0, @@ -92,10 +93,22 @@ typedef struct { /******************************************************************/ +guint +_nm_platform_signal_id_get (NMPlatformSignalIdType signal_type) +{ + nm_assert ( signal_type > 0 + && signal_type != NM_PLATFORM_SIGNAL_ID_NONE + && signal_type < _NM_PLATFORM_SIGNAL_ID_LAST); + + return signals[signal_type]; +} + +/******************************************************************/ + /* Singleton NMPlatform subclass instance and cached class object */ NM_DEFINE_SINGLETON_INSTANCE (NMPlatform); -NM_DEFINE_SINGLETON_WEAK_REF (NMPlatform); +NM_DEFINE_SINGLETON_REGISTER (NMPlatform); /* Just always initialize a @klass instance. NM_PLATFORM_GET_CLASS() * is only a plain read on the self instance, which the compiler @@ -137,9 +150,9 @@ nm_platform_setup (NMPlatform *instance) singleton_instance = instance; - nm_singleton_instance_weak_ref_register (); + nm_singleton_instance_register (); - nm_log_dbg (LOGD_CORE, "setup NMPlatform singleton (%p, %s)", instance, G_OBJECT_TYPE_NAME (instance)); + nm_log_dbg (LOGD_CORE, "setup %s singleton (%p, %s)", "NMPlatform", singleton_instance, G_OBJECT_TYPE_NAME (instance)); } /** @@ -204,22 +217,6 @@ nm_platform_error_to_string (NMPlatformError error) /******************************************************************/ -#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 (NMPlatform *self) { @@ -284,7 +281,6 @@ nm_platform_sysctl_set (NMPlatform *self, const char *path, const char *value) 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 (self, path, value); } @@ -336,7 +332,6 @@ nm_platform_sysctl_get (NMPlatform *self, const char *path) _CHECK_SELF (self, klass, NULL); g_return_val_if_fail (path, NULL); - g_return_val_if_fail (klass->sysctl_get, NULL); return klass->sysctl_get (self, path); } @@ -416,8 +411,6 @@ nm_platform_link_get_all (NMPlatform *self) _CHECK_SELF (self, klass, NULL); - g_return_val_if_fail (klass->link_get_all, NULL); - links = klass->link_get_all (self); if (!links || links->len == 0) @@ -427,7 +420,7 @@ nm_platform_link_get_all (NMPlatform *self) for (i = 0; i < links->len; i++) { item = &g_array_index (links, NMPlatformLink, i); - _LOGt ("link-get: %3d: %s", i, nm_platform_link_to_string (item)); + _LOGt ("link-get: %3d: %s", i, nm_platform_link_to_string (item, NULL, 0)); nm_assert (item->ifindex > 0 && !g_hash_table_contains (unseen, GINT_TO_POINTER (item->ifindex))); @@ -450,8 +443,7 @@ nm_platform_link_get_all (NMPlatform *self) if (item->parent != NM_PLATFORM_LINK_OTHER_NETNS) { g_warn_if_fail (item->parent > 0); g_warn_if_fail (item->parent != item->ifindex); - g_warn_if_fail ( !nm_platform_check_support_libnl_link_netnsid () - || g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent))); + g_warn_if_fail (g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent))); } } } @@ -483,7 +475,7 @@ nm_platform_link_get_all (NMPlatform *self) if (item->parent > 0 && g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent))) continue; - _LOGt ("link-get: add %3d -> %3d: %s", i, j, nm_platform_link_to_string (item)); + _LOGt ("link-get: add %3d -> %3d: %s", i, j, nm_platform_link_to_string (item, NULL, 0)); g_hash_table_remove (unseen, GINT_TO_POINTER (item->ifindex)); g_array_index (result, NMPlatformLink, j++) = *item; @@ -496,7 +488,7 @@ nm_platform_link_get_all (NMPlatform *self) * This can happen for veth pairs where each peer is parent of the other end. */ item = &g_array_index (links, NMPlatformLink, first_idx); - _LOGt ("link-get: add (loop) %3d -> %3d: %s", first_idx, j, nm_platform_link_to_string (item)); + _LOGt ("link-get: add (loop) %3d -> %3d: %s", first_idx, j, nm_platform_link_to_string (item, NULL, 0)); g_hash_table_remove (unseen, GINT_TO_POINTER (item->ifindex)); g_array_index (result, NMPlatformLink, j++) = *item; @@ -575,7 +567,7 @@ nm_platform_link_get_by_address (NMPlatform *self, } static NMPlatformError -_link_add_check_existing (NMPlatform *self, const char *name, NMLinkType type, NMPlatformLink *out_link) +_link_add_check_existing (NMPlatform *self, const char *name, NMLinkType type, const NMPlatformLink **out_link) { const NMPlatformLink *pllink; @@ -590,11 +582,13 @@ _link_add_check_existing (NMPlatform *self, const char *name, NMLinkType type, N wrong_type ? ", expected " : "", wrong_type ? nm_link_type_to_string (type) : ""); if (out_link) - *out_link = *pllink; + *out_link = pllink; if (wrong_type) return NM_PLATFORM_ERROR_WRONG_TYPE; return NM_PLATFORM_ERROR_EXISTS; } + if (out_link) + *out_link = NULL; return NM_PLATFORM_ERROR_SUCCESS; } @@ -623,14 +617,13 @@ nm_platform_link_add (NMPlatform *self, NMLinkType type, const void *address, size_t address_len, - NMPlatformLink *out_link) + const NMPlatformLink **out_link) { NMPlatformError plerr; _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); - g_return_val_if_fail (klass->link_add, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail ( (address != NULL) ^ (address_len == 0) , NM_PLATFORM_ERROR_BUG); plerr = _link_add_check_existing (self, name, type, out_link); @@ -644,7 +637,7 @@ nm_platform_link_add (NMPlatform *self, } /** - * nm_platform_dummy_add: + * nm_platform_link_dummy_add: * @self: platform instance * @name: New interface name * @out_link: on success, the link object @@ -652,7 +645,9 @@ nm_platform_link_add (NMPlatform *self, * Create a software ethernet-like interface */ NMPlatformError -nm_platform_dummy_add (NMPlatform *self, const char *name, NMPlatformLink *out_link) +nm_platform_link_dummy_add (NMPlatform *self, + const char *name, + const NMPlatformLink **out_link) { return nm_platform_link_add (self, name, NM_LINK_TYPE_DUMMY, NULL, 0, out_link); } @@ -746,8 +741,6 @@ nm_platform_link_get_type_name (NMPlatform *self, int ifindex) { _CHECK_SELF (self, klass, NULL); - g_return_val_if_fail (klass->link_get_type_name, NULL); - return klass->link_get_type_name (self, ifindex); } @@ -890,22 +883,19 @@ nm_platform_link_uses_arp (NMPlatform *self, int ifindex) gboolean nm_platform_link_get_ipv6_token (NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId *iid) { + const NMPlatformLink *pllink; + _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex >= 0, FALSE); g_return_val_if_fail (iid, FALSE); -#if HAVE_LIBNL_INET6_TOKEN - { - const NMPlatformLink *pllink; - pllink = nm_platform_link_get (self, ifindex); - if (pllink && pllink->inet6_token.is_valid) { - *iid = pllink->inet6_token.iid; - return TRUE; - } + pllink = nm_platform_link_get (self, ifindex); + if (pllink && pllink->inet6_token.is_valid) { + *iid = pllink->inet6_token.iid; + return TRUE; } -#endif return FALSE; } @@ -947,23 +937,18 @@ nm_platform_link_get_udev_device (NMPlatform *self, int ifindex) gboolean nm_platform_link_get_user_ipv6ll_enabled (NMPlatform *self, int ifindex) { + const NMPlatformLink *pllink; + _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex >= 0, FALSE); -#if HAVE_LIBNL_INET6_ADDR_GEN_MODE - { - const NMPlatformLink *pllink; - - pllink = nm_platform_link_get (self, ifindex); - if (pllink && pllink->inet6_addr_gen_mode_inv) - return _nm_platform_uint8_inv (pllink->inet6_addr_gen_mode_inv) == IN6_ADDR_GEN_MODE_NONE; - } -#endif + pllink = nm_platform_link_get (self, ifindex); + if (pllink && pllink->inet6_addr_gen_mode_inv) + return _nm_platform_uint8_inv (pllink->inet6_addr_gen_mode_inv) == NM_IN6_ADDR_GEN_MODE_NONE; return FALSE; } - /** * nm_platform_link_set_user_ip6vll_enabled: * @self: platform instance @@ -981,7 +966,6 @@ nm_platform_link_set_user_ipv6ll_enabled (NMPlatform *self, int ifindex, gboolea _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex >= 0, FALSE); - g_return_val_if_fail (klass->check_support_user_ipv6ll, FALSE); if (klass->link_set_user_ipv6ll_enabled) return klass->link_set_user_ipv6ll_enabled (self, ifindex, enabled); @@ -1004,7 +988,6 @@ nm_platform_link_set_address (NMPlatform *self, int ifindex, gconstpointer addre 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); _LOGD ("link: setting '%s' (%d) hardware address", nm_platform_link_get_name (self, ifindex), ifindex); return klass->link_set_address (self, ifindex, address, length); @@ -1083,7 +1066,6 @@ nm_platform_link_supports_carrier_detect (NMPlatform *self, int ifindex) _CHECK_SELF (self, klass, FALSE); 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 (self, ifindex); } @@ -1094,7 +1076,6 @@ nm_platform_link_supports_vlans (NMPlatform *self, int ifindex) _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex >= 0, FALSE); - g_return_val_if_fail (klass->link_supports_vlans, FALSE); return klass->link_supports_vlans (self, ifindex); } @@ -1113,7 +1094,6 @@ nm_platform_link_set_up (NMPlatform *self, int ifindex, gboolean *out_no_firmwar _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); - g_return_val_if_fail (klass->link_set_up, FALSE); _LOGD ("link: setting up '%s' (%d)", nm_platform_link_get_name (self, ifindex), ifindex); return klass->link_set_up (self, ifindex, out_no_firmware); @@ -1132,7 +1112,6 @@ nm_platform_link_set_down (NMPlatform *self, int ifindex) _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); - g_return_val_if_fail (klass->link_set_down, FALSE); _LOGD ("link: setting down '%s' (%d)", nm_platform_link_get_name (self, ifindex), ifindex); return klass->link_set_down (self, ifindex); @@ -1151,7 +1130,6 @@ nm_platform_link_set_arp (NMPlatform *self, int ifindex) _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex >= 0, FALSE); - g_return_val_if_fail (klass->link_set_arp, FALSE); _LOGD ("link: setting arp '%s' (%d)", nm_platform_link_get_name (self, ifindex), ifindex); return klass->link_set_arp (self, ifindex); @@ -1170,7 +1148,6 @@ nm_platform_link_set_noarp (NMPlatform *self, int ifindex) _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex >= 0, FALSE); - g_return_val_if_fail (klass->link_set_noarp, FALSE); _LOGD ("link: setting noarp '%s' (%d)", nm_platform_link_get_name (self, ifindex), ifindex); return klass->link_set_noarp (self, ifindex); @@ -1191,7 +1168,6 @@ nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu) 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); _LOGD ("link: setting '%s' (%d) mtu %"G_GUINT32_FORMAT, nm_platform_link_get_name (self, ifindex), ifindex, mtu); return klass->link_set_mtu (self, ifindex, mtu); @@ -1306,7 +1282,6 @@ nm_platform_link_get_driver_info (NMPlatform *self, _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex >= 0, FALSE); - g_return_val_if_fail (klass->link_get_driver_info, FALSE); return klass->link_get_driver_info (self, ifindex, @@ -1330,7 +1305,6 @@ nm_platform_link_enslave (NMPlatform *self, int master, int slave) 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); _LOGD ("link: enslaving '%s' (%d) to master '%s' (%d)", nm_platform_link_get_name (self, slave), slave, @@ -1353,7 +1327,6 @@ nm_platform_link_release (NMPlatform *self, int master, int slave) 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 (self, slave) != master) return FALSE; @@ -1384,8 +1357,109 @@ nm_platform_link_get_master (NMPlatform *self, int slave) return pllink ? pllink->master : 0; } +/*****************************************************************************/ + /** - * nm_platform_bridge_add: + * nm_platform_link_get_lnk: + * @self: the platform instance + * @ifindex: the link ifindex to lookup + * @link_type: filter by link-type. + * @out_link: (allow-none): returns the platform link instance + * + * If the function returns %NULL, that could mean that no such ifindex + * exists, of that the link has no lnk data. You can find that out + * by checking @out_link. @out_link will always be set if a link + * with @ifindex exists. + * + * If @link_type is %NM_LINK_TYPE_NONE, the function returns the lnk + * object if it is present. If you set link-type, you can be sure + * that only a link type of the matching type is returned (or %NULL). + * + * Returns: the internal link lnk object. The returned object + * is owned by the platform cache and must not be modified. Note + * however, that the object is guaranteed to be immutable, so + * you can savely take a reference and keep it for yourself + * (but don't modify it). + */ +const NMPObject * +nm_platform_link_get_lnk (NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link) +{ + _CHECK_SELF (self, klass, FALSE); + + NM_SET_OUT (out_link, NULL); + + g_return_val_if_fail (ifindex > 0, NULL); + + return klass->link_get_lnk (self, ifindex, link_type, out_link); +} + +static gconstpointer +_link_get_lnk (NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link) +{ + const NMPObject *lnk; + + lnk = nm_platform_link_get_lnk (self, ifindex, link_type, out_link); + return lnk ? &lnk->object : NULL; +} + +const NMPlatformLnkGre * +nm_platform_link_get_lnk_gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_GRE, out_link); +} + +const NMPlatformLnkInfiniband * +nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_INFINIBAND, out_link); +} + +const NMPlatformLnkIp6Tnl * +nm_platform_link_get_lnk_ip6tnl (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IP6TNL, out_link); +} + +const NMPlatformLnkIpIp * +nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_IPIP, out_link); +} + +const NMPlatformLnkMacvlan * +nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_MACVLAN, out_link); +} + +const NMPlatformLnkMacvtap * +nm_platform_link_get_lnk_macvtap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_MACVTAP, out_link); +} + +const NMPlatformLnkSit * +nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_SIT, out_link); +} + +const NMPlatformLnkVlan * +nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_VLAN, out_link); +} + +const NMPlatformLnkVxlan * +nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_VXLAN, out_link); +} + +/*****************************************************************************/ + +/** + * nm_platform_link_bridge_add: * @self: platform instance * @name: New interface name * @address: (allow-none): set the mac address of the new bridge @@ -1395,17 +1469,17 @@ nm_platform_link_get_master (NMPlatform *self, int slave) * Create a software bridge. */ NMPlatformError -nm_platform_bridge_add (NMPlatform *self, - const char *name, - const void *address, - size_t address_len, - NMPlatformLink *out_link) +nm_platform_link_bridge_add (NMPlatform *self, + const char *name, + const void *address, + size_t address_len, + const NMPlatformLink **out_link) { return nm_platform_link_add (self, name, NM_LINK_TYPE_BRIDGE, address, address_len, out_link); } /** - * nm_platform_bond_add: + * nm_platform_link_bond_add: * @self: platform instance * @name: New interface name * @out_link: on success, the link object @@ -1413,13 +1487,15 @@ nm_platform_bridge_add (NMPlatform *self, * Create a software bonding device. */ NMPlatformError -nm_platform_bond_add (NMPlatform *self, const char *name, NMPlatformLink *out_link) +nm_platform_link_bond_add (NMPlatform *self, + const char *name, + const NMPlatformLink **out_link) { return nm_platform_link_add (self, name, NM_LINK_TYPE_BOND, NULL, 0, out_link); } /** - * nm_platform_team_add: + * nm_platform_link_team_add: * @self: platform instance * @name: New interface name * @out_link: on success, the link object @@ -1427,13 +1503,15 @@ nm_platform_bond_add (NMPlatform *self, const char *name, NMPlatformLink *out_li * Create a software teaming device. */ NMPlatformError -nm_platform_team_add (NMPlatform *self, const char *name, NMPlatformLink *out_link) +nm_platform_link_team_add (NMPlatform *self, + const char *name, + const NMPlatformLink **out_link) { return nm_platform_link_add (self, name, NM_LINK_TYPE_TEAM, NULL, 0, out_link); } /** - * nm_platform_vlan_add: + * nm_platform_link_vlan_add: * @self: platform instance * @name: New interface name * @vlanid: VLAN identifier @@ -1443,12 +1521,12 @@ nm_platform_team_add (NMPlatform *self, const char *name, NMPlatformLink *out_li * Create a software VLAN device. */ NMPlatformError -nm_platform_vlan_add (NMPlatform *self, - const char *name, - int parent, - int vlanid, - guint32 vlanflags, - NMPlatformLink *out_link) +nm_platform_link_vlan_add (NMPlatform *self, + const char *name, + int parent, + int vlanid, + guint32 vlanflags, + const NMPlatformLink **out_link) { NMPlatformError plerr; @@ -1457,7 +1535,6 @@ nm_platform_vlan_add (NMPlatform *self, g_return_val_if_fail (parent >= 0, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail (vlanid >= 0, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); - g_return_val_if_fail (klass->vlan_add, NM_PLATFORM_ERROR_BUG); plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_VLAN, out_link); if (plerr != NM_PLATFORM_ERROR_SUCCESS) @@ -1470,98 +1547,321 @@ nm_platform_vlan_add (NMPlatform *self, return NM_PLATFORM_ERROR_SUCCESS; } +/** + * nm_platform_link_vxlan_add: + * @self: platform instance + * @name: New interface name + * @props: properties of the new link + * @out_link: on success, the link object + * + * Create a VXLAN device. + */ +NMPlatformError +nm_platform_link_vxlan_add (NMPlatform *self, + const char *name, + const NMPlatformLnkVxlan *props, + const NMPlatformLink **out_link) +{ + NMPlatformError plerr; + + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); + + plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_VXLAN, out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; + + _LOGD ("link: adding vxlan '%s' parent %d id %d", + name, props->parent_ifindex, props->id); + if (!klass->link_vxlan_add (self, name, props, out_link)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return NM_PLATFORM_ERROR_SUCCESS; +} + +/** + * nm_platform_link_tun_add: + * @self: platform instance + * @name: new interface name + * @tap: whether the interface is a TAP + * @owner: interface owner or -1 + * @group: interface group or -1 + * @pi: whether to clear the IFF_NO_PI flag + * @vnet_hdr: whether to set the IFF_VNET_HDR flag + * @multi_queue: whether to set the IFF_MULTI_QUEUE flag + * @out_link: on success, the link object + * + * Create a TUN or TAP interface. + */ +NMPlatformError +nm_platform_link_tun_add (NMPlatform *self, + const char *name, + gboolean tap, + gint64 owner, + gint64 group, + gboolean pi, + gboolean vnet_hdr, + gboolean multi_queue, + const NMPlatformLink **out_link) +{ + NMPlatformError plerr; + + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + + plerr = _link_add_check_existing (self, name, tap ? NM_LINK_TYPE_TAP : NM_LINK_TYPE_TUN, out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; + + _LOGD ("link: adding %s '%s' owner %" G_GINT64_FORMAT " group %" G_GINT64_FORMAT, + tap ? "tap" : "tun", name, owner, group); + if (!klass->tun_add (self, name, tap, owner, group, pi, vnet_hdr, multi_queue, out_link)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return NM_PLATFORM_ERROR_SUCCESS; +} + +/*****************************************************************************/ + +static char * +link_option_path (NMPlatform *self, int master, const char *category, const char *option) +{ + const char *name = nm_platform_link_get_name (self, 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 (NMPlatform *self, int master, const char *category, const char *option, const char *value) +{ + gs_free char *path = link_option_path (self, master, category, option); + + return path && nm_platform_sysctl_set (self, path, value); +} + +static char * +link_get_option (NMPlatform *self, int master, const char *category, const char *option) +{ + gs_free char *path = link_option_path (self, master, category, option); + + return path ? nm_platform_sysctl_get (self, path) : NULL; +} + +static const char * +master_category (NMPlatform *self, int master) +{ + switch (nm_platform_link_get_type (self, master)) { + case NM_LINK_TYPE_BRIDGE: + return "bridge"; + case NM_LINK_TYPE_BOND: + return "bonding"; + default: + return NULL; + } +} + +static const char * +slave_category (NMPlatform *self, int slave) +{ + int master = nm_platform_link_get_master (self, slave); + + if (master <= 0) + return NULL; + + switch (nm_platform_link_get_type (self, master)) { + case NM_LINK_TYPE_BRIDGE: + return "brport"; + default: + return NULL; + } +} + gboolean -nm_platform_master_set_option (NMPlatform *self, int ifindex, const char *option, const char *value) +nm_platform_sysctl_master_set_option (NMPlatform *self, int ifindex, const char *option, const char *value) { _CHECK_SELF (self, klass, FALSE); 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 (self, ifindex, option, value); + return link_set_option (self, ifindex, master_category (self, ifindex), option, value); } char * -nm_platform_master_get_option (NMPlatform *self, int ifindex, const char *option) +nm_platform_sysctl_master_get_option (NMPlatform *self, int ifindex, const char *option) { _CHECK_SELF (self, klass, NULL); 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 (self, ifindex, option); + return link_get_option (self, ifindex, master_category (self, ifindex), option); } gboolean -nm_platform_slave_set_option (NMPlatform *self, int ifindex, const char *option, const char *value) +nm_platform_sysctl_slave_set_option (NMPlatform *self, int ifindex, const char *option, const char *value) { _CHECK_SELF (self, klass, FALSE); 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 (self, ifindex, option, value); + return link_set_option (self, ifindex, slave_category (self, ifindex), option, value); } char * -nm_platform_slave_get_option (NMPlatform *self, int ifindex, const char *option) +nm_platform_sysctl_slave_get_option (NMPlatform *self, int ifindex, const char *option) { _CHECK_SELF (self, klass, NULL); 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 (self, ifindex, option); + return link_get_option (self, ifindex, slave_category (self, ifindex), option); } +/******************************************************************************/ + gboolean -nm_platform_vlan_get_info (NMPlatform *self, int ifindex, int *parent, int *vlanid) +nm_platform_link_vlan_change (NMPlatform *self, + int ifindex, + NMVlanFlags flags_mask, + NMVlanFlags flags_set, + gboolean ingress_reset_all, + const NMVlanQosMapping *ingress_map, + gsize n_ingress_map, + gboolean egress_reset_all, + const NMVlanQosMapping *egress_map, + gsize n_egress_map) { _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (klass->vlan_get_info, FALSE); + nm_assert (klass->link_vlan_change); - if (parent) - *parent = 0; - if (vlanid) - *vlanid = 0; + g_return_val_if_fail (!n_ingress_map || ingress_map, FALSE); + g_return_val_if_fail (!n_egress_map || egress_map, FALSE); - if (nm_platform_link_get_type (self, ifindex) != NM_LINK_TYPE_VLAN) - return FALSE; + flags_set &= flags_mask; + + if (_LOGD_ENABLED ()) { + char buf[512]; + char *b = buf; + gsize len, i; + + b[0] = '\0'; + len = sizeof (buf); + + if (flags_mask) + nm_utils_strbuf_append (&b, &len, " flags 0x%x/0x%x", (unsigned) flags_set, (unsigned) flags_mask); + + if (ingress_reset_all || n_ingress_map) { + nm_utils_strbuf_append_str (&b, &len, " ingress-qos-map"); + nm_platform_vlan_qos_mapping_to_string ("", ingress_map, n_ingress_map, b, len); + i = strlen (b); + b += i; + len -= i; + if (ingress_reset_all) + nm_utils_strbuf_append_str (&b, &len, " (reset-all)"); + } + + if (egress_reset_all || n_egress_map) { + nm_utils_strbuf_append_str (&b, &len, " egress-qos-map"); + nm_platform_vlan_qos_mapping_to_string ("", egress_map, n_egress_map, b, len); + i = strlen (b); + b += i; + len -= i; + if (egress_reset_all) + nm_utils_strbuf_append_str (&b, &len, " (reset-all)"); + } - return klass->vlan_get_info (self, ifindex, parent, vlanid); + _LOGD ("link: change vlan %d:%s", ifindex, buf); + } + return klass->link_vlan_change (self, + ifindex, + flags_mask, + flags_set, + ingress_reset_all, + ingress_map, + n_ingress_map, + egress_reset_all, + egress_map, + n_egress_map); } gboolean -nm_platform_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to) +nm_platform_link_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to) { - _CHECK_SELF (self, klass, FALSE); - - g_return_val_if_fail (klass->vlan_set_ingress_map, FALSE); + NMVlanQosMapping map = { + .from = from, + .to = to, + }; - _LOGD ("link: setting vlan ingress map for %d from %d to %d", ifindex, from, to); - return klass->vlan_set_ingress_map (self, ifindex, from, to); + return nm_platform_link_vlan_change (self, ifindex, 0, 0, FALSE, &map, 1, FALSE, NULL, 0); } gboolean -nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to) +nm_platform_link_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to) { - _CHECK_SELF (self, klass, FALSE); + NMVlanQosMapping map = { + .from = from, + .to = to, + }; - g_return_val_if_fail (klass->vlan_set_egress_map, FALSE); + return nm_platform_link_vlan_change (self, ifindex, 0, 0, FALSE, NULL, 0, FALSE, &map, 1); +} - _LOGD ("link: setting vlan egress map for %d from %d to %d", ifindex, from, to); - return klass->vlan_set_egress_map (self, ifindex, from, to); +/** + * nm_platform_link_gre_add: + * @self: platform instance + * @name: name of the new interface + * @props: interface properties + * @out_link: on success, the link object + * + * Create a software GRE device. + */ +NMPlatformError +nm_platform_link_gre_add (NMPlatform *self, + const char *name, + const NMPlatformLnkGre *props, + const NMPlatformLink **out_link) +{ + NMPlatformError plerr; + char buffer[INET_ADDRSTRLEN]; + + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); + g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + + plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_GRE, out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; + + _LOGD (LOG_FMT_IP_TUNNEL, + "gre", + name, + props->parent_ifindex, + nm_utils_inet4_ntop (props->local, NULL), + nm_utils_inet4_ntop (props->remote, buffer)); + + if (!klass->link_gre_add (self, name, props, out_link)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return NM_PLATFORM_ERROR_SUCCESS; } NMPlatformError -nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link) +nm_platform_link_infiniband_add (NMPlatform *self, + int parent, + int p_key, + const NMPlatformLink **out_link) { gs_free char *parent_name = NULL; gs_free char *name = NULL; @@ -1571,7 +1871,6 @@ nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, N g_return_val_if_fail (parent >= 0, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail (p_key >= 0, NM_PLATFORM_ERROR_BUG); - g_return_val_if_fail (klass->infiniband_partition_add, NM_PLATFORM_ERROR_BUG); parent_name = g_strdup (nm_platform_link_get_name (self, parent)); if ( !parent_name @@ -1591,73 +1890,330 @@ nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, N } gboolean -nm_platform_infiniband_get_info (NMPlatform *self, - int ifindex, - int *parent, - int *p_key, - const char **mode) -{ +nm_platform_link_infiniband_get_properties (NMPlatform *self, + int ifindex, + int *out_parent, + int *out_p_key, + const char **out_mode) +{ + const NMPlatformLnkInfiniband *plnk; + const NMPlatformLink *plink; + const char *iface; + char *path, *contents; + const char *mode; + int p_key = 0; + _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); - g_return_val_if_fail (klass->infiniband_get_info, FALSE); - return klass->infiniband_get_info (self, ifindex, parent, p_key, mode); + plnk = nm_platform_link_get_lnk_infiniband (self, ifindex, &plink); + + if ( !plink + || plink->type != NM_LINK_TYPE_INFINIBAND) + return FALSE; + + if (plnk) { + NM_SET_OUT (out_parent, plink->parent); + NM_SET_OUT (out_p_key, plnk->p_key); + NM_SET_OUT (out_mode, plnk->mode); + return TRUE; + } + + /* Could not get the link information via netlink. To support older kernels, + * fallback to reading sysfs. */ + + iface = ASSERT_VALID_PATH_COMPONENT (plink->name); + + /* Fall back to reading sysfs */ + path = g_strdup_printf ("/sys/class/net/%s/mode", iface); + contents = nm_platform_sysctl_get (self, path); + g_free (path); + if (!contents) + return FALSE; + + if (strstr (contents, "datagram")) + mode = "datagram"; + else if (strstr (contents, "connected")) + mode = "connected"; + else + mode = NULL; + g_free (contents); + + path = g_strdup_printf ("/sys/class/net/%s/pkey", iface); + contents = nm_platform_sysctl_get (self, path); + g_free (path); + if (!contents) + return FALSE; + p_key = (int) _nm_utils_ascii_str_to_int64 (contents, 16, 0, 0xFFFF, -1); + g_free (contents); + if (p_key < 0) + return FALSE; + + NM_SET_OUT (out_parent, plink->parent); + NM_SET_OUT (out_p_key, p_key); + NM_SET_OUT (out_mode, mode); + return TRUE; } -gboolean -nm_platform_veth_get_properties (NMPlatform *self, int ifindex, NMPlatformVethProperties *props) +/** + * nm_platform_ip6tnl_add: + * @self: platform instance + * @name: name of the new interface + * @props: interface properties + * @out_link: on success, the link object + * + * Create an IPv6 tunnel. + */ +NMPlatformError +nm_platform_link_ip6tnl_add (NMPlatform *self, + const char *name, + const NMPlatformLnkIp6Tnl *props, + const NMPlatformLink **out_link) { - _CHECK_SELF (self, klass, FALSE); + NMPlatformError plerr; + char buffer[INET6_ADDRSTRLEN]; - g_return_val_if_fail (ifindex > 0, FALSE); - g_return_val_if_fail (props != NULL, FALSE); + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); + g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + + plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_IP6TNL, out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; - return klass->veth_get_properties (self, ifindex, props); + _LOGD (LOG_FMT_IP_TUNNEL, + "ip6tnl", + name, + props->parent_ifindex, + nm_utils_inet6_ntop (&props->local, NULL), + nm_utils_inet6_ntop (&props->remote, buffer)); + + if (!klass->link_ip6tnl_add (self, name, props, out_link)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return NM_PLATFORM_ERROR_SUCCESS; } -gboolean -nm_platform_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *props) +/** + * nm_platform_ipip_add: + * @self: platform instance + * @name: name of the new interface + * @props: interface properties + * @out_link: on success, the link object + * + * Create an IPIP tunnel. + */ +NMPlatformError +nm_platform_link_ipip_add (NMPlatform *self, + const char *name, + const NMPlatformLnkIpIp *props, + const NMPlatformLink **out_link) { - _CHECK_SELF (self, klass, FALSE); + NMPlatformError plerr; + char buffer[INET_ADDRSTRLEN]; - g_return_val_if_fail (ifindex > 0, FALSE); - g_return_val_if_fail (props != NULL, FALSE); + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); - return klass->tun_get_properties (self, ifindex, props); + g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); + g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + + plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_IPIP, out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; + + _LOGD (LOG_FMT_IP_TUNNEL, + "ipip", + name, + props->parent_ifindex, + nm_utils_inet4_ntop (props->local, NULL), + nm_utils_inet4_ntop (props->remote, buffer)); + + if (!klass->link_ipip_add (self, name, props, out_link)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return NM_PLATFORM_ERROR_SUCCESS; +} + +/** + * nm_platform_macvlan_add: + * @self: platform instance + * @name: name of the new interface + * @props: interface properties + * @out_link: on success, the link object + * + * Create a MACVLAN or MACVTAP device. + */ +NMPlatformError +nm_platform_link_macvlan_add (NMPlatform *self, + const char *name, + int parent, + const NMPlatformLnkMacvlan *props, + const NMPlatformLink **out_link) +{ + NMPlatformError plerr; + NMLinkType type; + + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); + g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + + type = props->tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN; + + plerr = _link_add_check_existing (self, name, type, out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; + + _LOGD ("adding %s '%s' parent %u mode %u", + props->tap ? "macvtap" : "macvlan", + name, + parent, + props->mode); + + if (!klass->link_macvlan_add (self, name, parent, props, out_link)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return NM_PLATFORM_ERROR_SUCCESS; +} + +/** + * nm_platform_sit_add: + * @self: platform instance + * @name: name of the new interface + * @props: interface properties + * @out_link: on success, the link object + * + * Create a software SIT device. + */ +NMPlatformError +nm_platform_link_sit_add (NMPlatform *self, + const char *name, + const NMPlatformLnkSit *props, + const NMPlatformLink **out_link) +{ + NMPlatformError plerr; + char buffer[INET_ADDRSTRLEN]; + + _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); + + g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); + g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + + plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_SIT, out_link); + if (plerr != NM_PLATFORM_ERROR_SUCCESS) + return plerr; + + _LOGD (LOG_FMT_IP_TUNNEL, + "sit", + name, + props->parent_ifindex, + nm_utils_inet4_ntop (props->local, NULL), + nm_utils_inet4_ntop (props->remote, buffer)); + + if (!klass->link_sit_add (self, name, props, out_link)) + return NM_PLATFORM_ERROR_UNSPECIFIED; + return NM_PLATFORM_ERROR_SUCCESS; } gboolean -nm_platform_macvlan_get_properties (NMPlatform *self, int ifindex, NMPlatformMacvlanProperties *props) +nm_platform_link_veth_get_properties (NMPlatform *self, int ifindex, int *out_peer_ifindex) { + const NMPlatformLink *plink; + int peer_ifindex; _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (ifindex > 0, FALSE); - g_return_val_if_fail (props != NULL, FALSE); + plink = nm_platform_link_get (self, ifindex); + + if (!plink) + return FALSE; + if (plink->type != NM_LINK_TYPE_VETH) + return FALSE; + + if (plink->parent != 0) { + NM_SET_OUT (out_peer_ifindex, plink->parent); + return TRUE; + } + + /* Pre-4.1 kernel did not expose the peer_ifindex as IFA_LINK. Lookup via ethtool. */ + if (out_peer_ifindex) { + peer_ifindex = nmp_utils_ethtool_get_peer_ifindex (plink->name); + if (peer_ifindex <= 0) + return FALSE; - return klass->macvlan_get_properties (self, ifindex, props); + *out_peer_ifindex = peer_ifindex; + } + return TRUE; } gboolean -nm_platform_vxlan_get_properties (NMPlatform *self, int ifindex, NMPlatformVxlanProperties *props) +nm_platform_link_tun_get_properties_ifname (NMPlatform *self, const char *ifname, NMPlatformTunProperties *props) { + char *path, *val; + gboolean success = TRUE; + _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (ifindex > 0, FALSE); - g_return_val_if_fail (props != NULL, FALSE); + g_return_val_if_fail (props, FALSE); + + memset (props, 0, sizeof (*props)); + props->owner = -1; + props->group = -1; - return klass->vxlan_get_properties (self, ifindex, props); + 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 (self, 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 (self, 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 (self, path); + g_free (path); + if (val) { + gint64 flags; + + flags = _nm_utils_ascii_str_to_int64 (val, 16, 0, G_MAXINT64, 0); + if (!errno) { + props->mode = ((flags & (IFF_TUN | IFF_TAP)) == IFF_TUN) ? "tun" : "tap"; + props->no_pi = !!(flags & IFF_NO_PI); + props->vnet_hdr = !!(flags & IFF_VNET_HDR); + props->multi_queue = !!(flags & NM_IFF_MULTI_QUEUE); + } else + success = FALSE; + g_free (val); + } else + success = FALSE; + + return success; } gboolean -nm_platform_gre_get_properties (NMPlatform *self, int ifindex, NMPlatformGreProperties *props) +nm_platform_link_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *props) { _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); g_return_val_if_fail (props != NULL, FALSE); - return klass->gre_get_properties (self, ifindex, props); + return nm_platform_link_tun_get_properties_ifname (self, nm_platform_link_get_name (self, ifindex), props); } gboolean @@ -1680,16 +2236,6 @@ nm_platform_wifi_get_bssid (NMPlatform *self, int ifindex, guint8 *bssid) return klass->wifi_get_bssid (self, ifindex, bssid); } -GByteArray * -nm_platform_wifi_get_ssid (NMPlatform *self, int ifindex) -{ - _CHECK_SELF (self, klass, NULL); - - g_return_val_if_fail (ifindex > 0, NULL); - - return klass->wifi_get_ssid (self, ifindex); -} - guint32 nm_platform_wifi_get_frequency (NMPlatform *self, int ifindex) { @@ -1740,6 +2286,22 @@ nm_platform_wifi_set_mode (NMPlatform *self, int ifindex, NM80211Mode mode) klass->wifi_set_mode (self, ifindex, mode); } +static void +wifi_set_powersave (NMPlatform *p, int ifindex, guint32 powersave) +{ + /* empty */ +} + +void +nm_platform_wifi_set_powersave (NMPlatform *self, int ifindex, guint32 powersave) +{ + _CHECK_SELF_VOID (self, klass); + + g_return_if_fail (ifindex > 0); + + klass->wifi_set_powersave (self, ifindex, powersave); +} + guint32 nm_platform_wifi_find_frequency (NMPlatform *self, int ifindex, const guint32 *freqs) { @@ -1818,13 +2380,29 @@ _to_string_dev (NMPlatform *self, int ifindex, char *buf, size_t size) /******************************************************************/ +void +nm_platform_ip4_address_set_addr (NMPlatformIP4Address *addr, in_addr_t address, int plen) +{ + addr->address = address; + addr->peer_address = address; + addr->plen = plen; +} + +const struct in6_addr * +nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr) +{ + if ( IN6_IS_ADDR_UNSPECIFIED (&addr->peer_address) + || IN6_ARE_ADDR_EQUAL (&addr->peer_address, &addr->address)) + return &addr->address; + return &addr->peer_address; +} + GArray * nm_platform_ip4_address_get_all (NMPlatform *self, int ifindex) { _CHECK_SELF (self, klass, NULL); 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 (self, ifindex); } @@ -1835,17 +2413,16 @@ nm_platform_ip6_address_get_all (NMPlatform *self, int ifindex) _CHECK_SELF (self, klass, NULL); 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 (self, ifindex); } gboolean nm_platform_ip4_address_add (NMPlatform *self, - int ifindex, + int ifindex, in_addr_t address, - in_addr_t peer_address, int plen, + in_addr_t peer_address, guint32 lifetime, guint32 preferred, const char *label) @@ -1856,7 +2433,6 @@ nm_platform_ip4_address_add (NMPlatform *self, 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 (_LOGD_ENABLED ()) { @@ -1872,17 +2448,17 @@ nm_platform_ip4_address_add (NMPlatform *self, if (label) g_strlcpy (addr.label, label, sizeof (addr.label)); - _LOGD ("address: adding or updating IPv4 address: %s", nm_platform_ip4_address_to_string (&addr)); + _LOGD ("address: adding or updating IPv4 address: %s", nm_platform_ip4_address_to_string (&addr, NULL, 0)); } - return klass->ip4_address_add (self, ifindex, address, peer_address, plen, lifetime, preferred, label); + return klass->ip4_address_add (self, ifindex, address, plen, peer_address, lifetime, preferred, label); } gboolean nm_platform_ip6_address_add (NMPlatform *self, int ifindex, struct in6_addr address, - struct in6_addr peer_address, int plen, + struct in6_addr peer_address, guint32 lifetime, guint32 preferred, guint flags) @@ -1893,7 +2469,6 @@ nm_platform_ip6_address_add (NMPlatform *self, 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 (_LOGD_ENABLED ()) { NMPlatformIP6Address addr = { 0 }; @@ -1907,28 +2482,27 @@ nm_platform_ip6_address_add (NMPlatform *self, addr.preferred = preferred; addr.flags = flags; - _LOGD ("address: adding or updating IPv6 address: %s", nm_platform_ip6_address_to_string (&addr)); + _LOGD ("address: adding or updating IPv6 address: %s", nm_platform_ip6_address_to_string (&addr, NULL, 0)); } - return klass->ip6_address_add (self, ifindex, address, peer_address, plen, lifetime, preferred, flags); + return klass->ip6_address_add (self, ifindex, address, plen, peer_address, lifetime, preferred, flags); } gboolean nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_t address, int plen, in_addr_t peer_address) { char str_dev[TO_STRING_DEV_BUF_SIZE]; - char str_peer[NM_UTILS_INET_ADDRSTRLEN]; + char str_peer2[NM_UTILS_INET_ADDRSTRLEN]; + char str_peer[100]; _CHECK_SELF (self, klass, FALSE); 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); - _LOGD ("address: deleting IPv4 address %s/%d, %s%s%sifindex %d%s", + _LOGD ("address: deleting IPv4 address %s/%d, %sifindex %d%s", nm_utils_inet4_ntop (address, NULL), plen, - peer_address ? "peer " : "", - peer_address ? nm_utils_inet4_ntop (peer_address, str_peer) : "", - peer_address ? ", " : "", + peer_address != address + ? nm_sprintf_buf (str_peer, "peer %s, ", nm_utils_inet4_ntop (peer_address, str_peer2)) : "", ifindex, _to_string_dev (self, ifindex, str_dev, sizeof (str_dev))); return klass->ip4_address_delete (self, ifindex, address, plen, peer_address); @@ -1943,7 +2517,6 @@ nm_platform_ip6_address_delete (NMPlatform *self, int ifindex, struct in6_addr a 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); _LOGD ("address: deleting IPv6 address %s/%d, ifindex %d%s", nm_utils_inet6_ntop (&address, NULL), plen, ifindex, @@ -1952,21 +2525,21 @@ nm_platform_ip6_address_delete (NMPlatform *self, int ifindex, struct in6_addr a } const NMPlatformIP4Address * -nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, int plen) +nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, int plen, guint32 peer_address) { - _CHECK_SELF (self, klass, FALSE); + _CHECK_SELF (self, klass, NULL); - g_return_val_if_fail (plen > 0, FALSE); + g_return_val_if_fail (plen > 0, NULL); - return klass->ip4_address_get (self, ifindex, address, plen); + return klass->ip4_address_get (self, ifindex, address, plen, peer_address); } const NMPlatformIP6Address * nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address, int plen) { - _CHECK_SELF (self, klass, FALSE); + _CHECK_SELF (self, klass, NULL); - g_return_val_if_fail (plen > 0, FALSE); + g_return_val_if_fail (plen > 0, NULL); return klass->ip6_address_get (self, ifindex, address, plen); } @@ -1980,7 +2553,9 @@ array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address for (i = 0; i < len; i++) { NMPlatformIP4Address *candidate = &g_array_index (addresses, NMPlatformIP4Address, i); - if (candidate->address == address->address && candidate->plen == address->plen) { + if ( candidate->address == address->address + && candidate->plen == address->plen + && ((candidate->peer_address ^ address->peer_address) & nm_utils_ip4_prefix_to_netmask (address->plen)) == 0) { guint32 lifetime, preferred; if (nmp_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred, @@ -2064,7 +2639,7 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known now, ADDRESS_LIFETIME_PADDING, &lifetime, &preferred)) continue; - if (!nm_platform_ip4_address_add (self, ifindex, known_address->address, known_address->peer_address, known_address->plen, lifetime, preferred, known_address->label)) + if (!nm_platform_ip4_address_add (self, ifindex, known_address->address, known_address->plen, known_address->peer_address, lifetime, preferred, known_address->label)) return FALSE; if (out_added_addresses) { @@ -2125,7 +2700,7 @@ nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known continue; if (!nm_platform_ip6_address_add (self, ifindex, known_address->address, - known_address->peer_address, known_address->plen, + known_address->plen, known_address->peer_address, lifetime, preferred, known_address->flags)) return FALSE; } @@ -2164,17 +2739,46 @@ nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRoute return klass->ip6_route_get_all (self, ifindex, flags); } +/** + * nm_platform_ip4_route_add: + * @self: + * @ifindex: + * @source: + * network: + * plen: + * gateway: + * pref_src: + * metric: + * mss: + * + * For kernel, a gateway can be either explicitly set or left + * at zero (0.0.0.0). In addition, there is the scope of the IPv4 + * route. + * When adding a route with + * $ ip route add default dev $IFNAME + * the resulting route will have gateway 0.0.0.0 and scope "link". + * Contrary to + * $ ip route add default via 0.0.0.0 dev $IFNAME + * which adds the route with scope "global". + * + * NetworkManager's Platform can currently only add on-link-routes with scope + * "link" (and gateway 0.0.0.0) or gateway-routes with scope "global" (and + * gateway not 0.0.0.0). + * + * It does not support adding globally scoped routes via 0.0.0.0. + * + * Returns: %TRUE in case of success. + */ gboolean nm_platform_ip4_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source, in_addr_t network, int plen, - in_addr_t gateway, guint32 pref_src, + in_addr_t gateway, in_addr_t pref_src, guint32 metric, guint32 mss) { _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (0 <= plen && plen <= 32, FALSE); - g_return_val_if_fail (klass->ip4_route_add, FALSE); if (_LOGD_ENABLED ()) { NMPlatformIP4Route route = { 0 }; @@ -2188,7 +2792,7 @@ nm_platform_ip4_route_add (NMPlatform *self, route.mss = mss; route.pref_src = pref_src; - _LOGD ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route)); + _LOGD ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route, NULL, 0)); } return klass->ip4_route_add (self, ifindex, source, network, plen, gateway, pref_src, metric, mss); } @@ -2202,7 +2806,6 @@ nm_platform_ip6_route_add (NMPlatform *self, _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (0 <= plen && plen <= 128, FALSE); - g_return_val_if_fail (klass->ip6_route_add, FALSE); if (_LOGD_ENABLED ()) { NMPlatformIP6Route route = { 0 }; @@ -2215,7 +2818,7 @@ nm_platform_ip6_route_add (NMPlatform *self, route.metric = metric; route.mss = mss; - _LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (&route)); + _LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (&route, NULL, 0)); } return klass->ip6_route_add (self, ifindex, source, network, plen, gateway, metric, mss); } @@ -2227,8 +2830,6 @@ nm_platform_ip4_route_delete (NMPlatform *self, int ifindex, in_addr_t network, _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (klass->ip4_route_delete, FALSE); - _LOGD ("route: deleting IPv4 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s", nm_utils_inet4_ntop (network, NULL), plen, metric, ifindex, _to_string_dev (self, ifindex, str_dev, sizeof (str_dev))); @@ -2242,8 +2843,6 @@ nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6_addr net _CHECK_SELF (self, klass, FALSE); - g_return_val_if_fail (klass->ip6_route_delete, FALSE); - _LOGD ("route: deleting IPv6 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s", nm_utils_inet6_ntop (&network, NULL), plen, metric, ifindex, _to_string_dev (self, ifindex, str_dev, sizeof (str_dev))); @@ -2268,6 +2867,40 @@ nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr networ /******************************************************************/ +const char * +nm_platform_vlan_qos_mapping_to_string (const char *name, + const NMVlanQosMapping *map, + gsize n_map, + char *buf, + gsize len) +{ + gsize i; + char *b; + + nm_utils_to_string_buffer_init (&buf, &len); + + if (!n_map) { + nm_utils_strbuf_append_str (&buf, &len, ""); + return buf; + } + + if (!map) + g_return_val_if_reached (""); + + b = buf; + + if (name) { + nm_utils_strbuf_append_str (&b, &len, name); + nm_utils_strbuf_append_str (&b, &len, " {"); + } else + nm_utils_strbuf_append_c (&b, &len, '{'); + + for (i = 0; i < n_map; i++) + nm_utils_strbuf_append (&b, &len, " %u:%u", map[i].from, map[i].to); + nm_utils_strbuf_append_str (&b, &len, " }"); + return buf; +} + static const char * source_to_string (NMIPConfigSource source) { @@ -2320,21 +2953,29 @@ _lifetime_summary_to_string (gint32 now, guint32 timestamp, guint32 preferred, g return buf; } -char _nm_platform_to_string_buffer[256]; - +/** + * nm_platform_link_to_string: + * @route: pointer to NMPlatformLink address structure + * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used. + * @len: the size of the @buf. If @buf is %NULL, this argument is ignored. + * + * A method for converting an link struct into a string representation. + * + * Returns: a string representation of the link. + */ const char * -nm_platform_link_to_string (const NMPlatformLink *link) +nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len) { char master[20]; char parent[20]; - char str_vlan[16]; GString *str_flags; char str_addrmode[30]; gs_free char *str_addr = NULL; gs_free char *str_inet6_token = NULL; + const char *str_link_type; - if (!link) - return "(unknown link)"; + if (!nm_utils_to_string_buffer_init_null (link, &buf, &len)) + return buf; str_flags = g_string_new (NULL); if (NM_FLAGS_HAS (link->flags, IFF_NOARP)) @@ -2349,7 +2990,7 @@ nm_platform_link_to_string (const NMPlatformLink *link) if (link->flags) { char str_flags_buf[64]; - rtnl_link_flags2str (link->flags, str_flags_buf, sizeof (str_flags_buf)); + nm_platform_link_flags2str (link->flags, str_flags_buf, sizeof (str_flags_buf)); g_string_append_printf (str_flags, ";%s", str_flags_buf); } @@ -2365,11 +3006,6 @@ nm_platform_link_to_string (const NMPlatformLink *link) else parent[0] = 0; - if (link->vlan_id) - g_snprintf (str_vlan, sizeof (str_vlan), " vlan %u", (guint) link->vlan_id); - else - str_vlan[0] = '\0'; - if (link->inet6_addr_gen_mode_inv) { switch (_nm_platform_uint8_inv (link->inet6_addr_gen_mode_inv)) { case 0: @@ -2390,14 +3026,15 @@ nm_platform_link_to_string (const NMPlatformLink *link) if (link->inet6_token.is_valid) str_inet6_token = nm_utils_hwaddr_ntoa (&link->inet6_token.iid, sizeof (link->inet6_token.iid)); - g_snprintf (_nm_platform_to_string_buffer, sizeof (_nm_platform_to_string_buffer), + str_link_type = nm_link_type_to_string (link->type); + + g_snprintf (buf, len, "%d: " /* ifindex */ "%s" /* name */ "%s" /* parent */ " <%s>" /* flags */ " mtu %d" "%s" /* master */ - "%s" /* vlan */ " arp %u" /* arptype */ "%s%s" /* link->type */ "%s%s" /* kind */ @@ -2412,12 +3049,11 @@ nm_platform_link_to_string (const NMPlatformLink *link) parent, str_flags->str, link->mtu, master, - str_vlan, link->arptype, - nm_link_type_to_string (link->type) ? " " : "", - str_if_set (nm_link_type_to_string (link->type), "???"), - link->kind ? (g_strcmp0 (nm_link_type_to_string (link->type), link->kind) ? "/" : "*") : "", - link->kind && g_strcmp0 (nm_link_type_to_string (link->type), link->kind) ? link->kind : "", + str_link_type ? " " : "", + str_if_set (str_link_type, "???"), + link->kind ? (g_strcmp0 (str_link_type, link->kind) ? "/" : "*") : "", + link->kind && g_strcmp0 (str_link_type, link->kind) ? link->kind : "", link->initialized ? " init" : " not-init", str_addrmode, str_addr ? " addr " : "", @@ -2427,23 +3063,313 @@ nm_platform_link_to_string (const NMPlatformLink *link) link->driver ? " driver " : "", link->driver ? link->driver : ""); g_string_free (str_flags, TRUE); - return _nm_platform_to_string_buffer; + return buf; +} + +const char * +nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len) +{ + char str_local[30]; + char str_local1[NM_UTILS_INET_ADDRSTRLEN]; + char str_remote[30]; + char str_remote1[NM_UTILS_INET_ADDRSTRLEN]; + char str_ttl[30]; + char str_tos[30]; + char str_parent_ifindex[30]; + char str_input_flags[30]; + char str_output_flags[30]; + char str_input_key[30]; + char str_input_key1[NM_UTILS_INET_ADDRSTRLEN]; + char str_output_key[30]; + char str_output_key1[NM_UTILS_INET_ADDRSTRLEN]; + + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + g_snprintf (buf, len, + "gre" + "%s" /* remote */ + "%s" /* local */ + "%s" /* parent_ifindex */ + "%s" /* ttl */ + "%s" /* tos */ + "%s" /* path_mtu_discovery */ + "%s" /* iflags */ + "%s" /* oflags */ + "%s" /* ikey */ + "%s" /* okey */ + "", + lnk->remote ? nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet4_ntop (lnk->remote, str_remote1)) : "", + lnk->local ? nm_sprintf_buf (str_local, " local %s", nm_utils_inet4_ntop (lnk->local, str_local1)) : "", + lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "", + lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit", + lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf (str_tos, " tos 0x%x", lnk->tos)) : "", + lnk->path_mtu_discovery ? "" : " nopmtudisc", + lnk->input_flags ? nm_sprintf_buf (str_input_flags, " iflags 0x%x", lnk->input_flags) : "", + lnk->output_flags ? nm_sprintf_buf (str_output_flags, " oflags 0x%x", lnk->output_flags) : "", + NM_FLAGS_HAS (lnk->input_flags, GRE_KEY) || lnk->input_key ? nm_sprintf_buf (str_input_key, " ikey %s", nm_utils_inet4_ntop (lnk->input_key, str_input_key1)) : "", + NM_FLAGS_HAS (lnk->output_flags, GRE_KEY) || lnk->output_key ? nm_sprintf_buf (str_output_key, " okey %s", nm_utils_inet4_ntop (lnk->output_key, str_output_key1)) : ""); + return buf; +} + +const char * +nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *buf, gsize len) +{ + char str_p_key[64]; + + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + g_snprintf (buf, len, + "infiniband" + "%s" /* p_key */ + "%s%s" /* mode */ + "", + lnk->p_key ? nm_sprintf_buf (str_p_key, " pkey %d", lnk->p_key) : "", + lnk->mode ? " mode " : "", + lnk->mode ?: ""); + return buf; +} + +const char * +nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsize len) +{ + char str_local[30]; + char str_local1[NM_UTILS_INET_ADDRSTRLEN]; + char str_remote[30]; + char str_remote1[NM_UTILS_INET_ADDRSTRLEN]; + char str_ttl[30]; + char str_tclass[30]; + char str_flow[30]; + char str_encap[30]; + char str_proto[30]; + char str_parent_ifindex[30]; + + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + g_snprintf (buf, len, + "ip6tnl" + "%s" /* remote */ + "%s" /* local */ + "%s" /* parent_ifindex */ + "%s" /* ttl */ + "%s" /* tclass */ + "%s" /* encap limit */ + "%s" /* flow label */ + "%s" /* proto */ + "", + nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet6_ntop (&lnk->remote, str_remote1)), + nm_sprintf_buf (str_local, " local %s", nm_utils_inet6_ntop (&lnk->local, str_local1)), + lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "", + lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit", + lnk->tclass == 1 ? " tclass inherit" : nm_sprintf_buf (str_tclass, " tclass 0x%x", lnk->tclass), + nm_sprintf_buf (str_encap, " encap-limit %u", lnk->encap_limit), + nm_sprintf_buf (str_flow, " flow-label 0x05%x", lnk->flow_label), + nm_sprintf_buf (str_proto, " proto %u", lnk->proto)); + return buf; +} + +const char * +nm_platform_lnk_ipip_to_string (const NMPlatformLnkIpIp *lnk, char *buf, gsize len) +{ + char str_local[30]; + char str_local1[NM_UTILS_INET_ADDRSTRLEN]; + char str_remote[30]; + char str_remote1[NM_UTILS_INET_ADDRSTRLEN]; + char str_ttl[30]; + char str_tos[30]; + char str_parent_ifindex[30]; + + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + g_snprintf (buf, len, + "ipip" + "%s" /* remote */ + "%s" /* local */ + "%s" /* parent_ifindex */ + "%s" /* ttl */ + "%s" /* tos */ + "%s" /* path_mtu_discovery */ + "", + lnk->remote ? nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet4_ntop (lnk->remote, str_remote1)) : "", + lnk->local ? nm_sprintf_buf (str_local, " local %s", nm_utils_inet4_ntop (lnk->local, str_local1)) : "", + lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "", + lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit", + lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf (str_tos, " tos 0x%x", lnk->tos)) : "", + lnk->path_mtu_discovery ? "" : " nopmtudisc"); + return buf; +} + +const char * +nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len) +{ + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + g_snprintf (buf, len, + "macvlan mode %u %s", + lnk->mode, + lnk->no_promisc ? "not-promisc" : "promisc"); + return buf; +} + +const char * +nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len) +{ + char str_local[30]; + char str_local1[NM_UTILS_INET_ADDRSTRLEN]; + char str_remote[30]; + char str_remote1[NM_UTILS_INET_ADDRSTRLEN]; + char str_ttl[30]; + char str_tos[30]; + char str_flags[30]; + char str_proto[30]; + char str_parent_ifindex[30]; + + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + g_snprintf (buf, len, + "sit" + "%s" /* remote */ + "%s" /* local */ + "%s" /* parent_ifindex */ + "%s" /* ttl */ + "%s" /* tos */ + "%s" /* path_mtu_discovery */ + "%s" /* flags */ + "%s" /* proto */ + "", + lnk->remote ? nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet4_ntop (lnk->remote, str_remote1)) : "", + lnk->local ? nm_sprintf_buf (str_local, " local %s", nm_utils_inet4_ntop (lnk->local, str_local1)) : "", + lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "", + lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit", + lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf (str_tos, " tos 0x%x", lnk->tos)) : "", + lnk->path_mtu_discovery ? "" : " nopmtudisc", + lnk->flags ? nm_sprintf_buf (str_flags, " flags 0x%x", lnk->flags) : "", + lnk->proto ? nm_sprintf_buf (str_proto, " proto 0x%x", lnk->proto) : ""); + return buf; +} + +const char * +nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len) +{ + char *b; + + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + b = buf; + + nm_utils_strbuf_append (&b, &len, "vlan %u", lnk->id); + if (lnk->flags) + nm_utils_strbuf_append (&b, &len, " flags 0x%x", lnk->flags); + return buf; +} + +const char * +nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len) +{ + char str_group[100]; + char str_group6[100]; + char str_local[100]; + char str_local6[100]; + char str_dev[25]; + char str_limit[25]; + char str_src_port[35]; + char str_dst_port[25]; + char str_tos[25]; + char str_ttl[25]; + + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + if (lnk->group == 0) + str_group[0] = '\0'; + else { + g_snprintf (str_group, sizeof (str_group), + " %s %s", + IN_MULTICAST (ntohl (lnk->group)) ? "group" : "remote", + nm_utils_inet4_ntop (lnk->group, NULL)); + } + if (IN6_IS_ADDR_UNSPECIFIED (&lnk->group6)) + str_group6[0] = '\0'; + else { + g_snprintf (str_group6, sizeof (str_group6), + " %s%s %s", + IN6_IS_ADDR_MULTICAST (&lnk->group6) ? "group" : "remote", + str_group[0] ? "6" : "", /* usually, a vxlan has either v4 or v6 only. */ + nm_utils_inet6_ntop (&lnk->group6, NULL)); + } + + if (lnk->local == 0) + str_local[0] = '\0'; + else { + g_snprintf (str_local, sizeof (str_local), + " local %s", + nm_utils_inet4_ntop (lnk->local, NULL)); + } + if (IN6_IS_ADDR_UNSPECIFIED (&lnk->local6)) + str_local6[0] = '\0'; + else { + g_snprintf (str_local6, sizeof (str_local6), + " local%s %s", + str_local[0] ? "6" : "", /* usually, a vxlan has either v4 or v6 only. */ + nm_utils_inet6_ntop (&lnk->local6, NULL)); + } + + g_snprintf (buf, len, + "vxlan" + " id %u" /* id */ + "%s%s" /* group/group6 */ + "%s%s" /* local/local6 */ + "%s" /* dev */ + "%s" /* src_port_min/src_port_max */ + "%s" /* dst_port */ + "%s" /* learning */ + "%s" /* proxy */ + "%s" /* rsc */ + "%s" /* l2miss */ + "%s" /* l3miss */ + "%s" /* tos */ + "%s" /* ttl */ + " ageing %u" /* ageing */ + "%s" /* limit */ + "", + (guint) lnk->id, + str_group, str_group6, + str_local, str_local6, + lnk->parent_ifindex ? nm_sprintf_buf (str_dev, " dev %d", lnk->parent_ifindex) : "", + lnk->src_port_min || lnk->src_port_max ? nm_sprintf_buf (str_src_port, " srcport %u %u", lnk->src_port_min, lnk->src_port_max) : "", + lnk->dst_port ? nm_sprintf_buf (str_dst_port, " dstport %u", lnk->dst_port) : "", + !lnk->learning ? " nolearning" : "", + lnk->proxy ? " proxy" : "", + lnk->rsc ? " rsc" : "", + lnk->l2miss ? " l2miss" : "", + lnk->l3miss ? " l3miss" : "", + lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf (str_tos, " tos %#x", lnk->tos), + lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : "", + lnk->ageing, + lnk->limit ? nm_sprintf_buf (str_limit, " maxaddr %u", lnk->limit) : ""); + return buf; } /** * nm_platform_ip4_address_to_string: * @route: pointer to NMPlatformIP4Address address structure + * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used. + * @len: the size of the @buf. If @buf is %NULL, this argument is ignored. * * 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. + * Returns: a string representation of the address. */ const char * -nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address) +nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len) { char s_address[INET_ADDRSTRLEN]; char s_peer[INET_ADDRSTRLEN]; @@ -2454,11 +3380,12 @@ nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address) 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)"); + if (!nm_utils_to_string_buffer_init_null (address, &buf, &len)) + return buf; inet_ntop (AF_INET, &address->address, s_address, sizeof (s_address)); - if (address->peer_address) { + if (address->peer_address != address->address) { inet_ntop (AF_INET, &address->peer_address, s_peer, sizeof (s_peer)); str_peer = g_strconcat (" ptp ", s_peer, NULL); } @@ -2480,66 +3407,92 @@ nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address) 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 (_nm_platform_to_string_buffer, sizeof (_nm_platform_to_string_buffer), "%s/%d lft %s pref %s%s%s%s%s src %s", + g_snprintf (buf, len, + "%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 _nm_platform_to_string_buffer; + return buf; } -/** - * 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_UTILS_FLAGS2STR_DEFINE (nm_platform_link_flags2str, unsigned, + NM_UTILS_FLAGS2STR (IFF_LOOPBACK, "loopback"), + NM_UTILS_FLAGS2STR (IFF_BROADCAST, "broadcast"), + NM_UTILS_FLAGS2STR (IFF_POINTOPOINT, "pointopoint"), + NM_UTILS_FLAGS2STR (IFF_MULTICAST, "multicast"), + NM_UTILS_FLAGS2STR (IFF_NOARP, "noarp"), + NM_UTILS_FLAGS2STR (IFF_ALLMULTI, "allmulti"), + NM_UTILS_FLAGS2STR (IFF_PROMISC, "promisc"), + NM_UTILS_FLAGS2STR (IFF_MASTER, "master"), + NM_UTILS_FLAGS2STR (IFF_SLAVE, "slave"), + NM_UTILS_FLAGS2STR (IFF_DEBUG, "debug"), + NM_UTILS_FLAGS2STR (IFF_DYNAMIC, "dynamic"), + NM_UTILS_FLAGS2STR (IFF_AUTOMEDIA, "automedia"), + NM_UTILS_FLAGS2STR (IFF_PORTSEL, "portsel"), + NM_UTILS_FLAGS2STR (IFF_NOTRAILERS, "notrailers"), + NM_UTILS_FLAGS2STR (IFF_UP, "up"), + NM_UTILS_FLAGS2STR (IFF_RUNNING, "running"), + NM_UTILS_FLAGS2STR (IFF_LOWER_UP, "lowerup"), + NM_UTILS_FLAGS2STR (IFF_DORMANT, "dormant"), + NM_UTILS_FLAGS2STR (IFF_ECHO, "echo"), +); + +NM_UTILS_ENUM2STR_DEFINE (nm_platform_link_inet6_addrgenmode2str, guint8, + NM_UTILS_ENUM2STR (NM_IN6_ADDR_GEN_MODE_NONE, "none"), + NM_UTILS_ENUM2STR (NM_IN6_ADDR_GEN_MODE_EUI64, "eui64"), + NM_UTILS_ENUM2STR (NM_IN6_ADDR_GEN_MODE_STABLE_PRIVACY, "stable-privacy"), +); + +NM_UTILS_FLAGS2STR_DEFINE (nm_platform_addr_flags2str, unsigned, + NM_UTILS_FLAGS2STR (IFA_F_SECONDARY, "secondary"), + NM_UTILS_FLAGS2STR (IFA_F_NODAD, "nodad"), + NM_UTILS_FLAGS2STR (IFA_F_OPTIMISTIC, "optimistic"), + NM_UTILS_FLAGS2STR (IFA_F_HOMEADDRESS, "homeaddress"), + NM_UTILS_FLAGS2STR (IFA_F_DEPRECATED, "deprecated"), + NM_UTILS_FLAGS2STR (IFA_F_TENTATIVE, "tentative"), + NM_UTILS_FLAGS2STR (IFA_F_PERMANENT, "permanent"), + NM_UTILS_FLAGS2STR (IFA_F_MANAGETEMPADDR, "mngtmpaddr"), + NM_UTILS_FLAGS2STR (IFA_F_NOPREFIXROUTE, "noprefixroute"), +); + +NM_UTILS_ENUM2STR_DEFINE (nm_platform_route_scope2str, int, + NM_UTILS_ENUM2STR (RT_SCOPE_NOWHERE, "nowhere"), + NM_UTILS_ENUM2STR (RT_SCOPE_HOST, "host"), + NM_UTILS_ENUM2STR (RT_SCOPE_LINK, "link"), + NM_UTILS_ENUM2STR (RT_SCOPE_SITE, "site"), + NM_UTILS_ENUM2STR (RT_SCOPE_UNIVERSE, "global"), +); /** * nm_platform_ip6_address_to_string: * @route: pointer to NMPlatformIP6Address address structure + * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used. + * @len: the size of the @buf. If @buf is %NULL, this argument is ignored. * * 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. + * Returns: a string representation of the address. */ const char * -nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address) +nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *buf, gsize len) { +#define S_FLAGS_PREFIX " flags " 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)"); + if (!nm_utils_to_string_buffer_init_null (address, &buf, &len)) + return buf; inet_ntop (AF_INET6, &address->address, s_address, sizeof (s_address)); @@ -2550,9 +3503,11 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address) _to_string_dev (NULL, 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; + nm_platform_addr_flags2str (address->flags, &s_flags[STRLEN (S_FLAGS_PREFIX)], sizeof (s_flags) - STRLEN (S_FLAGS_PREFIX)); + if (s_flags[STRLEN (S_FLAGS_PREFIX)] == '\0') + s_flags[0] = '\0'; + else + memcpy (s_flags, S_FLAGS_PREFIX, STRLEN (S_FLAGS_PREFIX)); str_lft_p = _lifetime_to_string (address->timestamp, address->lifetime ? address->lifetime : NM_PLATFORM_LIFETIME_PERMANENT, @@ -2564,45 +3519,46 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address) 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 (_nm_platform_to_string_buffer, sizeof (_nm_platform_to_string_buffer), "%s/%d lft %s pref %s%s%s%s%s src %s", + g_snprintf (buf, len, + "%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 : "", + s_flags, source_to_string (address->source)); - g_free (str_flags); g_free (str_peer); - return _nm_platform_to_string_buffer; + return buf; } /** * nm_platform_ip4_route_to_string: * @route: pointer to NMPlatformIP4Route route structure + * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used. + * @len: the size of the @buf. If @buf is %NULL, this argument is ignored. * * 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. + * Returns: a string representation of the route. */ const char * -nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route) +nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsize len) { char s_network[INET_ADDRSTRLEN], s_gateway[INET_ADDRSTRLEN]; char s_pref_src[INET_ADDRSTRLEN]; char str_dev[TO_STRING_DEV_BUF_SIZE]; char str_scope[30]; - g_return_val_if_fail (route, "(unknown)"); + if (!nm_utils_to_string_buffer_init_null (route, &buf, &len)) + return buf; 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 (NULL, route->ifindex, str_dev, sizeof (str_dev)); - g_snprintf (_nm_platform_to_string_buffer, sizeof (_nm_platform_to_string_buffer), + g_snprintf (buf, len, "%s/%d" " via %s" "%s" @@ -2619,38 +3575,39 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route) route->mss, source_to_string (route->source), route->scope_inv ? " scope " : "", - route->scope_inv ? (rtnl_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "", + route->scope_inv ? (nm_platform_route_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "", route->pref_src ? " pref-src " : "", route->pref_src ? inet_ntop (AF_INET, &route->pref_src, s_pref_src, sizeof(s_pref_src)) : ""); - return _nm_platform_to_string_buffer; + return buf; } /** * nm_platform_ip6_route_to_string: * @route: pointer to NMPlatformIP6Route route structure + * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used. + * @len: the size of the @buf. If @buf is %NULL, this argument is ignored. * * 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. + * Returns: a string representation of the route. */ const char * -nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route) +nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len) { char s_network[INET6_ADDRSTRLEN], s_gateway[INET6_ADDRSTRLEN]; char str_dev[TO_STRING_DEV_BUF_SIZE]; - g_return_val_if_fail (route, "(unknown)"); + if (!nm_utils_to_string_buffer_init_null (route, &buf, &len)) + return buf; 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 (NULL, route->ifindex, str_dev, sizeof (str_dev)); - g_snprintf (_nm_platform_to_string_buffer, sizeof (_nm_platform_to_string_buffer), + g_snprintf (buf, len, "%s/%d" " via %s" "%s" @@ -2664,10 +3621,10 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route) route->metric, route->mss, source_to_string (route->source)); - return _nm_platform_to_string_buffer; + return buf; } -#define _CMP_POINTER(a, b) \ +#define _CMP_SELF(a, b) \ G_STMT_START { \ if ((a) == (b)) \ return 0; \ @@ -2677,6 +3634,19 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route) return 1; \ } G_STMT_END +#define _CMP_DIRECT(a, b) \ + G_STMT_START { \ + if ((a) != (b)) \ + return ((a) < (b)) ? -1 : 1; \ + } G_STMT_END + +#define _CMP_DIRECT_MEMCMP(a, b, size) \ + G_STMT_START { \ + int c = memcmp ((a), (b), (size)); \ + if (c != 0) \ + return c < 0 ? -1 : 1; \ + } G_STMT_END + #define _CMP_FIELD(a, b, field) \ G_STMT_START { \ if (((a)->field) != ((b)->field)) \ @@ -2732,13 +3702,12 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route) int nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b) { - _CMP_POINTER (a, b); + _CMP_SELF (a, b); _CMP_FIELD (a, b, ifindex); _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, vlan_id); _CMP_FIELD (a, b, flags); _CMP_FIELD (a, b, connected); _CMP_FIELD (a, b, mtu); @@ -2756,15 +3725,127 @@ nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b) return 0; } +int +nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b) +{ + _CMP_SELF (a, b); + _CMP_FIELD (a, b, parent_ifindex); + _CMP_FIELD (a, b, input_flags); + _CMP_FIELD (a, b, output_flags); + _CMP_FIELD (a, b, input_key); + _CMP_FIELD (a, b, output_key); + _CMP_FIELD (a, b, local); + _CMP_FIELD (a, b, remote); + _CMP_FIELD (a, b, ttl); + _CMP_FIELD (a, b, tos); + _CMP_FIELD_BOOL (a, b, path_mtu_discovery); + return 0; +} + +int +nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b) +{ + _CMP_SELF (a, b); + _CMP_FIELD (a, b, p_key); + _CMP_FIELD_STR_INTERNED (a, b, mode); + return 0; +} + +int +nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6Tnl *b) +{ + _CMP_SELF (a, b); + _CMP_FIELD (a, b, parent_ifindex); + _CMP_FIELD_MEMCMP (a, b, local); + _CMP_FIELD_MEMCMP (a, b, remote); + _CMP_FIELD (a, b, ttl); + _CMP_FIELD (a, b, tclass); + _CMP_FIELD (a, b, encap_limit); + _CMP_FIELD (a, b, flow_label); + _CMP_FIELD (a, b, proto); + return 0; +} + +int +nm_platform_lnk_ipip_cmp (const NMPlatformLnkIpIp *a, const NMPlatformLnkIpIp *b) +{ + _CMP_SELF (a, b); + _CMP_FIELD (a, b, parent_ifindex); + _CMP_FIELD (a, b, local); + _CMP_FIELD (a, b, remote); + _CMP_FIELD (a, b, ttl); + _CMP_FIELD (a, b, tos); + _CMP_FIELD_BOOL (a, b, path_mtu_discovery); + return 0; +} + +int +nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b) +{ + _CMP_SELF (a, b); + _CMP_FIELD (a, b, mode); + _CMP_FIELD_BOOL (a, b, no_promisc); + return 0; +} + +int +nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b) +{ + _CMP_SELF (a, b); + _CMP_FIELD (a, b, parent_ifindex); + _CMP_FIELD (a, b, local); + _CMP_FIELD (a, b, remote); + _CMP_FIELD (a, b, ttl); + _CMP_FIELD (a, b, tos); + _CMP_FIELD_BOOL (a, b, path_mtu_discovery); + _CMP_FIELD (a, b, flags); + _CMP_FIELD (a, b, proto); + return 0; +} + +int +nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b) +{ + _CMP_SELF (a, b); + _CMP_FIELD (a, b, id); + _CMP_FIELD (a, b, flags); + return 0; +} + +int +nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b) +{ + _CMP_SELF (a, b); + _CMP_FIELD (a, b, parent_ifindex); + _CMP_FIELD (a, b, id); + _CMP_FIELD (a, b, group); + _CMP_FIELD (a, b, local); + _CMP_FIELD_MEMCMP (a, b, group6); + _CMP_FIELD_MEMCMP (a, b, local6); + _CMP_FIELD (a, b, tos); + _CMP_FIELD (a, b, ttl); + _CMP_FIELD_BOOL (a, b, learning); + _CMP_FIELD (a, b, ageing); + _CMP_FIELD (a, b, limit); + _CMP_FIELD (a, b, dst_port); + _CMP_FIELD (a, b, src_port_min); + _CMP_FIELD (a, b, src_port_max); + _CMP_FIELD_BOOL (a, b, proxy); + _CMP_FIELD_BOOL (a, b, rsc); + _CMP_FIELD_BOOL (a, b, l2miss); + _CMP_FIELD_BOOL (a, b, l3miss); + return 0; +} + int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b) { - _CMP_POINTER (a, b); + _CMP_SELF (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, peer_address); _CMP_FIELD (a, b, timestamp); _CMP_FIELD (a, b, lifetime); _CMP_FIELD (a, b, preferred); @@ -2775,11 +3856,17 @@ nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4A int nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b) { - _CMP_POINTER (a, b); + const struct in6_addr *p_a, *p_b; + + _CMP_SELF (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); + + p_a = nm_platform_ip6_address_get_peer (a); + p_b = nm_platform_ip6_address_get_peer (b); + _CMP_DIRECT_MEMCMP (p_a, p_b, sizeof (*p_a)); + _CMP_FIELD (a, b, plen); _CMP_FIELD (a, b, timestamp); _CMP_FIELD (a, b, lifetime); @@ -2791,7 +3878,7 @@ nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6A int nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b) { - _CMP_POINTER (a, b); + _CMP_SELF (a, b); _CMP_FIELD (a, b, ifindex); _CMP_FIELD (a, b, source); _CMP_FIELD (a, b, network); @@ -2807,7 +3894,7 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b) { - _CMP_POINTER (a, b); + _CMP_SELF (a, b); _CMP_FIELD (a, b, ifindex); _CMP_FIELD (a, b, source); _CMP_FIELD_MEMCMP (a, b, network); @@ -2818,9 +3905,6 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route return 0; } -#undef _CMP_FIELD -#undef _CMP_FIELD_MEMCMP - /** * nm_platform_ip_address_cmp_expiry: * @a: a NMPlatformIPAddress to compare @@ -2839,7 +3923,7 @@ nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPlatfor { gint64 ta = 0, tb = 0; - _CMP_POINTER (a, b); + _CMP_SELF (a, b); if (a->lifetime == NM_PLATFORM_LIFETIME_PERMANENT || a->lifetime == 0) ta = G_MAXINT64; @@ -2872,8 +3956,6 @@ nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPlatfor return ta < tb ? -1 : 1; } -#undef _CMP_POINTER - const char * nm_platform_signal_change_type_to_string (NMPlatformSignalChangeType change_type) { @@ -2893,31 +3975,31 @@ static void log_link (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformLink *device, NMPlatformSignalChangeType change_type, gpointer user_data) { - _LOGD ("signal: link %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_link_to_string (device)); + _LOGD ("signal: link %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_link_to_string (device, NULL, 0)); } static void log_ip4_address (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformIP4Address *address, NMPlatformSignalChangeType change_type, gpointer user_data) { - _LOGD ("signal: address 4 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip4_address_to_string (address)); + _LOGD ("signal: address 4 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip4_address_to_string (address, NULL, 0)); } static void log_ip6_address (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformIP6Address *address, NMPlatformSignalChangeType change_type, gpointer user_data) { - _LOGD ("signal: address 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_address_to_string (address)); + _LOGD ("signal: address 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_address_to_string (address, NULL, 0)); } static void log_ip4_route (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformIP4Route *route, NMPlatformSignalChangeType change_type, gpointer user_data) { - _LOGD ("signal: route 4 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip4_route_to_string (route)); + _LOGD ("signal: route 4 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip4_route_to_string (route, NULL, 0)); } static void log_ip6_route (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformIP6Route *route, NMPlatformSignalChangeType change_type, gpointer user_data) { - _LOGD ("signal: route 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_route_to_string (route)); + _LOGD ("signal: route 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_route_to_string (route, NULL, 0)); } /******************************************************************/ @@ -2994,7 +4076,7 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v4 = { .addr_family = AF_INET, .sizeof_route = sizeof (NMPlatformIP4Route), .route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b)) nm_platform_ip4_route_cmp, - .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route)) nm_platform_ip4_route_to_string, + .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip4_route_to_string, .route_get_all = nm_platform_ip4_route_get_all, .route_add = _vtr_v4_route_add, .route_delete = _vtr_v4_route_delete, @@ -3007,7 +4089,7 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v6 = { .addr_family = AF_INET6, .sizeof_route = sizeof (NMPlatformIP6Route), .route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b)) nm_platform_ip6_route_cmp, - .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route)) nm_platform_ip6_route_to_string, + .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip6_route_to_string, .route_get_all = nm_platform_ip6_route_get_all, .route_add = _vtr_v6_route_add, .route_delete = _vtr_v6_route_delete, @@ -3051,14 +4133,6 @@ 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, 5, NM_TYPE_POBJECT_TYPE, 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) { @@ -3069,6 +4143,8 @@ nm_platform_class_init (NMPlatformClass *platform_class) object_class->set_property = set_property; object_class->constructed = constructed; + platform_class->wifi_set_powersave = wifi_set_powersave; + g_object_class_install_property (object_class, PROP_REGISTER_SINGLETON, g_param_spec_boolean (NM_PLATFORM_REGISTER_SINGLETON, "", "", @@ -3077,10 +4153,21 @@ nm_platform_class_init (NMPlatformClass *platform_class) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); +#define SIGNAL(signal, signal_id, method) \ + G_STMT_START { \ + signals[signal] = \ + g_signal_new_class_handler (""signal_id"", \ + G_OBJECT_CLASS_TYPE (object_class), \ + G_SIGNAL_RUN_FIRST, \ + G_CALLBACK (method), \ + NULL, NULL, NULL, \ + G_TYPE_NONE, 4, NM_TYPE_POBJECT_TYPE, G_TYPE_INT, G_TYPE_POINTER, NM_TYPE_PLATFORM_SIGNAL_CHANGE_TYPE); \ + } G_STMT_END + /* 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) + SIGNAL (NM_PLATFORM_SIGNAL_ID_LINK, NM_PLATFORM_SIGNAL_LINK_CHANGED, log_link); + SIGNAL (NM_PLATFORM_SIGNAL_ID_IP4_ADDRESS, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, log_ip4_address); + SIGNAL (NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, log_ip6_address); + SIGNAL (NM_PLATFORM_SIGNAL_ID_IP4_ROUTE, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, log_ip4_route); + SIGNAL (NM_PLATFORM_SIGNAL_ID_IP6_ROUTE, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, log_ip6_route); } diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 3219dd5a..8ac129a0 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -21,15 +21,16 @@ #ifndef __NETWORKMANAGER_PLATFORM_H__ #define __NETWORKMANAGER_PLATFORM_H__ -#include -#include "nm-glib-compat.h" #include #include #include +#include -#include -#include "nm-types.h" +#include "nm-dbus-interface.h" +#include "nm-default.h" #include "NetworkManagerUtils.h" +#include "nm-setting-vlan.h" +#include "nm-core-types-internal.h" #define NM_TYPE_PLATFORM (nm_platform_get_type ()) #define NM_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PLATFORM, NMPlatform)) @@ -54,6 +55,18 @@ typedef struct _NMPlatform NMPlatform; #define IFA_F_NOPREFIXROUTE 0x200 #endif +/* Define of the IN6_ADDR_GEN_MODE_* values to workaround old kernel headers + * that don't define it. */ +#define NM_IN6_ADDR_GEN_MODE_UNKNOWN 255 /* no corresponding value. */ +#define NM_IN6_ADDR_GEN_MODE_EUI64 0 /* IN6_ADDR_GEN_MODE_EUI64 */ +#define NM_IN6_ADDR_GEN_MODE_NONE 1 /* IN6_ADDR_GEN_MODE_NONE */ +#define NM_IN6_ADDR_GEN_MODE_STABLE_PRIVACY 2 /* IN6_ADDR_GEN_MODE_STABLE_PRIVACY */ + +#define NM_IFF_MULTI_QUEUE 0x0100 /* IFF_MULTI_QUEUE */ + +/* Redefine this in host's endianness */ +#define NM_GRE_KEY 0x2000 + typedef enum { /*< skip >*/ /* dummy value, to enforce that the enum type is signed and has a size @@ -74,18 +87,18 @@ typedef enum { /*< skip >*/ 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, - - /* Internal reason to suppress announcing change events */ - _NM_PLATFORM_REASON_CACHE_CHECK_INTERNAL, -} NMPlatformReason; + +typedef struct { + union { + guint8 addr_ptr[1]; + in_addr_t addr4; + struct in6_addr addr6; + }; +} NMIPAddr; + +extern const NMIPAddr nm_ip_addr_zero; + +#define NMIPAddrInit { .addr6 = IN6ADDR_ANY_INIT } #define NM_PLATFORM_LINK_OTHER_NETNS (-1) @@ -133,9 +146,6 @@ struct _NMPlatformLink { * initialized with memset(0) has and unset value.*/ guint8 inet6_addr_gen_mode_inv; - /* rtnl_link_vlan_get_id(), IFLA_VLAN_ID */ - guint16 vlan_id; - /* IFF_* flags as u32. Note that ifi_flags in 'struct ifinfomsg' is declared as 'unsigned', * but libnl stores the flag internally as u32. */ guint32 flags; @@ -147,6 +157,18 @@ struct _NMPlatformLink { guint mtu; }; +typedef enum { /*< skip >*/ + NM_PLATFORM_SIGNAL_ID_NONE, + NM_PLATFORM_SIGNAL_ID_LINK, + NM_PLATFORM_SIGNAL_ID_IP4_ADDRESS, + NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS, + NM_PLATFORM_SIGNAL_ID_IP4_ROUTE, + NM_PLATFORM_SIGNAL_ID_IP6_ROUTE, + _NM_PLATFORM_SIGNAL_ID_LAST, +} NMPlatformSignalIdType; + +guint _nm_platform_signal_id_get (NMPlatformSignalIdType signal_type); + typedef enum { NM_PLATFORM_SIGNAL_NONE, NM_PLATFORM_SIGNAL_ADDED, @@ -220,11 +242,23 @@ typedef struct { **/ struct _NMPlatformIP4Address { __NMPlatformIPAddress_COMMON; + + /* The local address IFA_LOCAL. */ in_addr_t address; + + /* The IFA_ADDRESS PTP peer address. This field is rather important, because + * it constitutes the identifier for the IPv4 address (e.g. you can add two + * addresses that only differ by their peer's network-part. + * + * Beware that for most cases, NetworkManager doesn't want to set an explicit + * peer-address. Hoever, that corresponds to setting the peer address to @address + * itself. Leaving peer-address unset/zero, means explicitly setting the peer + * address to 0.0.0.0, which you probably don't want. + * */ in_addr_t peer_address; /* PTP peer address */ + char label[IFNAMSIZ]; }; -G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPAddress, address_ptr) == G_STRUCT_OFFSET (NMPlatformIP4Address, address)); /** * NMPlatformIP6Address: @@ -236,7 +270,6 @@ struct _NMPlatformIP6Address { struct in6_addr peer_address; guint flags; /* ifa_flags from , field type "unsigned int" is as used in rtnl_addr_get_flags. */ }; -G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPAddress, address_ptr) == G_STRUCT_OFFSET (NMPlatformIP6Address, address)); typedef union { NMPlatformIPAddress ax; @@ -291,16 +324,14 @@ struct _NMPlatformIP4Route { /* RTA_PREFSRC/rtnl_route_get_pref_src(). A value of zero means that * no pref-src is set. */ - guint32 pref_src; + in_addr_t pref_src; }; -G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OFFSET (NMPlatformIP4Route, network)); struct _NMPlatformIP6Route { __NMPlatformIPRoute_COMMON; struct in6_addr network; struct in6_addr gateway; }; -G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OFFSET (NMPlatformIP6Route, network)); typedef union { NMPlatformIPRoute rx; @@ -319,7 +350,7 @@ typedef struct { int addr_family; gsize sizeof_route; int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b); - const char *(*route_to_string) (const NMPlatformIPXRoute *route); + const char *(*route_to_string) (const NMPlatformIPXRoute *route, char *buf, gsize len); GArray *(*route_get_all) (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); gboolean (*route_add) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric); gboolean (*route_delete) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route); @@ -330,26 +361,68 @@ typedef struct { extern const NMPlatformVTableRoute nm_platform_vtable_route_v4; extern const NMPlatformVTableRoute nm_platform_vtable_route_v6; -extern char _nm_platform_to_string_buffer[256]; - typedef struct { - int peer; -} NMPlatformVethProperties; + 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; +} NMPlatformLnkGre; typedef struct { - gint64 owner; - gint64 group; + int p_key; const char *mode; - gboolean no_pi; - gboolean vnet_hdr; - gboolean multi_queue; -} NMPlatformTunProperties; +} NMPlatformLnkInfiniband; typedef struct { int parent_ifindex; - const char *mode; + struct in6_addr local; + struct in6_addr remote; + guint8 ttl; + guint8 tclass; + guint8 encap_limit; + guint flow_label; + guint8 proto; +} NMPlatformLnkIp6Tnl; + +typedef struct { + int parent_ifindex; + in_addr_t local; + in_addr_t remote; + guint8 ttl; + guint8 tos; + gboolean path_mtu_discovery; +} NMPlatformLnkIpIp; + +typedef struct { + guint mode; gboolean no_promisc; -} NMPlatformMacvlanProperties; + gboolean tap; +} NMPlatformLnkMacvlan; + +typedef NMPlatformLnkMacvlan NMPlatformLnkMacvtap; + +typedef struct { + int parent_ifindex; + in_addr_t local; + in_addr_t remote; + guint8 ttl; + guint8 tos; + gboolean path_mtu_discovery; + guint16 flags; + guint8 proto; +} NMPlatformLnkSit; + +typedef struct { + /* rtnl_link_vlan_get_id(), IFLA_VLAN_ID */ + guint16 id; + NMVlanFlags flags; +} NMPlatformLnkVlan; typedef struct { int parent_ifindex; @@ -370,51 +443,19 @@ typedef struct { gboolean rsc; gboolean l2miss; gboolean l3miss; -} NMPlatformVxlanProperties; +} NMPlatformLnkVxlan; 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; + gint64 owner; + gint64 group; + const char *mode; + gboolean no_pi; + gboolean vnet_hdr; + gboolean multi_queue; +} NMPlatformTunProperties; /******************************************************************/ -/* 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. - */ - struct _NMPlatform { GObject parent; }; @@ -429,13 +470,15 @@ typedef struct { const NMPlatformLink *(*link_get_by_ifname) (NMPlatform *platform, const char *ifname); const NMPlatformLink *(*link_get_by_address) (NMPlatform *platform, gconstpointer address, size_t length); + const NMPObject *(*link_get_lnk) (NMPlatform *platform, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link); + GArray *(*link_get_all) (NMPlatform *); gboolean (*link_add) (NMPlatform *, const char *name, NMLinkType type, const void *address, size_t address_len, - NMPlatformLink *out_link); + const NMPlatformLink **out_link); gboolean (*link_delete) (NMPlatform *, int ifindex); const char *(*link_get_type_name) (NMPlatform *, int ifindex); gboolean (*link_get_unmanaged) (NMPlatform *, int ifindex, gboolean *unmanaged); @@ -474,28 +517,48 @@ typedef struct { gboolean (*link_enslave) (NMPlatform *, int master, int slave); gboolean (*link_release) (NMPlatform *, int master, 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, NMPlatformLink *out_link); - 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, NMPlatformLink *out_link); - gboolean (*infiniband_get_info) (NMPlatform *, - int ifindex, - int *parent, - int *p_key, - const char **mode); - - 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 (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags, const NMPlatformLink **out_link); + gboolean (*link_vlan_change) (NMPlatform *self, + int ifindex, + NMVlanFlags flags_mask, + NMVlanFlags flags_set, + gboolean ingress_reset_all, + const NMVlanQosMapping *ingress_map, + gsize n_ingress_map, + gboolean egress_reset_all, + const NMVlanQosMapping *egress_map, + gsize n_egress_map); + gboolean (*link_vxlan_add) (NMPlatform *, + const char *name, + const NMPlatformLnkVxlan *props, + const NMPlatformLink **out_link); + gboolean (*link_gre_add) (NMPlatform *, + const char *name, + const NMPlatformLnkGre *props, + const NMPlatformLink **out_link); + gboolean (*link_ip6tnl_add) (NMPlatform *, + const char *name, + const NMPlatformLnkIp6Tnl *props, + const NMPlatformLink **out_link); + gboolean (*link_ipip_add) (NMPlatform *, + const char *name, + const NMPlatformLnkIpIp *props, + const NMPlatformLink **out_link); + gboolean (*link_macvlan_add) (NMPlatform *, + const char *name, + int parent, + const NMPlatformLnkMacvlan *props, + const NMPlatformLink **out_link); + gboolean (*link_sit_add) (NMPlatform *, + const char *name, + const NMPlatformLnkSit *props, + const NMPlatformLink **out_link); + + gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, const NMPlatformLink **out_link); + + gboolean (*tun_add) (NMPlatform *platform, const char *name, gboolean tap, gint64 owner, gint64 group, gboolean pi, + gboolean vnet_hdr, gboolean multi_queue, const NMPlatformLink **out_link); gboolean (*wifi_get_capabilities) (NMPlatform *, int ifindex, NMDeviceWifiCapabilities *caps); gboolean (*wifi_get_bssid) (NMPlatform *, int ifindex, guint8 *bssid); @@ -505,6 +568,7 @@ typedef struct { guint32 (*wifi_get_rate) (NMPlatform *, int ifindex); NM80211Mode (*wifi_get_mode) (NMPlatform *, int ifindex); void (*wifi_set_mode) (NMPlatform *, int ifindex, NM80211Mode mode); + void (*wifi_set_powersave) (NMPlatform *, int ifindex, guint32 powersave); guint32 (*wifi_find_frequency) (NMPlatform *, int ifindex, const guint32 *freqs); void (*wifi_indicate_addressing_running) (NMPlatform *, int ifindex, gboolean running); @@ -514,23 +578,32 @@ typedef struct { 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, + gboolean (*ip4_address_add) (NMPlatform *, + int ifindex, + in_addr_t address, + int plen, + in_addr_t peer_address, + 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 (*ip6_address_add) (NMPlatform *, + int ifindex, + struct in6_addr address, + int plen, + struct in6_addr peer_address, + guint32 lifetime, + guint32 preferred_lft, + guint flags); gboolean (*ip4_address_delete) (NMPlatform *, int ifindex, in_addr_t address, int plen, in_addr_t peer_address); gboolean (*ip6_address_delete) (NMPlatform *, int ifindex, struct in6_addr address, int plen); - const NMPlatformIP4Address *(*ip4_address_get) (NMPlatform *, int ifindex, in_addr_t address, int plen); + const NMPlatformIP4Address *(*ip4_address_get) (NMPlatform *, int ifindex, in_addr_t address, int plen, in_addr_t peer_address); const NMPlatformIP6Address *(*ip6_address_get) (NMPlatform *, int ifindex, struct in6_addr address, int plen); GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags); GArray * (*ip6_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags); gboolean (*ip4_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source, in_addr_t network, int plen, in_addr_t gateway, - guint32 pref_src, guint32 metric, guint32 mss); + in_addr_t pref_src, guint32 metric, guint32 mss); gboolean (*ip6_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source, struct in6_addr network, int plen, struct in6_addr gateway, guint32 metric, guint32 mss); @@ -607,10 +680,10 @@ const NMPlatformLink *nm_platform_link_get_by_ifname (NMPlatform *self, const ch const NMPlatformLink *nm_platform_link_get_by_address (NMPlatform *self, gconstpointer address, size_t length); GArray *nm_platform_link_get_all (NMPlatform *self); -NMPlatformError nm_platform_dummy_add (NMPlatform *self, const char *name, NMPlatformLink *out_link); -NMPlatformError nm_platform_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len, NMPlatformLink *out_link); -NMPlatformError nm_platform_bond_add (NMPlatform *self, const char *name, NMPlatformLink *out_link); -NMPlatformError nm_platform_team_add (NMPlatform *self, const char *name, NMPlatformLink *out_link); +NMPlatformError nm_platform_link_dummy_add (NMPlatform *self, const char *name, const NMPlatformLink **out_link); +NMPlatformError nm_platform_link_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len, const NMPlatformLink **out_link); +NMPlatformError nm_platform_link_bond_add (NMPlatform *self, const char *name, const NMPlatformLink **out_link); +NMPlatformError nm_platform_link_team_add (NMPlatform *self, const char *name, const NMPlatformLink **out_link); gboolean nm_platform_link_delete (NMPlatform *self, int ifindex); /* convienience methods to lookup the link and access fields of NMPlatformLink. */ @@ -663,33 +736,77 @@ gboolean nm_platform_link_supports_vlans (NMPlatform *self, int ifindex); gboolean nm_platform_link_enslave (NMPlatform *self, int master, int slave); gboolean nm_platform_link_release (NMPlatform *self, int master, int slave); -gboolean nm_platform_master_set_option (NMPlatform *self, int ifindex, const char *option, const char *value); -char *nm_platform_master_get_option (NMPlatform *self, int ifindex, const char *option); -gboolean nm_platform_slave_set_option (NMPlatform *self, int ifindex, const char *option, const char *value); -char *nm_platform_slave_get_option (NMPlatform *self, int ifindex, const char *option); - -NMPlatformError nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags, NMPlatformLink *out_link); -gboolean nm_platform_vlan_get_info (NMPlatform *self, int ifindex, int *parent, int *vlanid); -gboolean nm_platform_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to); -gboolean nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to); -NMPlatformError nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link); -gboolean nm_platform_infiniband_get_info (NMPlatform *self, int ifindex, int *parent, int *p_key, const char **mode); - -gboolean nm_platform_veth_get_properties (NMPlatform *self, int ifindex, NMPlatformVethProperties *properties); -gboolean nm_platform_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *properties); -gboolean nm_platform_macvlan_get_properties (NMPlatform *self, int ifindex, NMPlatformMacvlanProperties *props); -gboolean nm_platform_vxlan_get_properties (NMPlatform *self, int ifindex, NMPlatformVxlanProperties *props); -gboolean nm_platform_gre_get_properties (NMPlatform *self, int ifindex, NMPlatformGreProperties *props); +gboolean nm_platform_sysctl_master_set_option (NMPlatform *self, int ifindex, const char *option, const char *value); +char *nm_platform_sysctl_master_get_option (NMPlatform *self, int ifindex, const char *option); +gboolean nm_platform_sysctl_slave_set_option (NMPlatform *self, int ifindex, const char *option, const char *value); +char *nm_platform_sysctl_slave_get_option (NMPlatform *self, int ifindex, const char *option); + +const NMPObject *nm_platform_link_get_lnk (NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link); +const NMPlatformLnkGre *nm_platform_link_get_lnk_gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkIp6Tnl *nm_platform_link_get_lnk_ip6tnl (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkInfiniband *nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkIpIp *nm_platform_link_get_lnk_ipip (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkMacvlan *nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkMacvtap *nm_platform_link_get_lnk_macvtap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkSit *nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); + +NMPlatformError nm_platform_link_vlan_add (NMPlatform *self, + const char *name, + int parent, + int vlanid, + guint32 vlanflags, + const NMPlatformLink **out_link); +gboolean nm_platform_link_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to); +gboolean nm_platform_link_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to); +gboolean nm_platform_link_vlan_change (NMPlatform *self, + int ifindex, + NMVlanFlags flags_mask, + NMVlanFlags flags_set, + gboolean ingress_reset_all, + const NMVlanQosMapping *ingress_map, + gsize n_ingress_map, + gboolean egress_reset_all, + const NMVlanQosMapping *egress_map, + gsize n_egress_map); + +NMPlatformError nm_platform_link_vxlan_add (NMPlatform *self, + const char *name, + const NMPlatformLnkVxlan *props, + const NMPlatformLink **out_link); + +NMPlatformError nm_platform_link_tun_add (NMPlatform *self, + const char *name, + gboolean tap, + gint64 owner, + gint64 group, + gboolean pi, + gboolean vnet_hdr, + gboolean multi_queue, + const NMPlatformLink **out_link); + +NMPlatformError nm_platform_link_infiniband_add (NMPlatform *self, + int parent, + int p_key, + const NMPlatformLink **out_link); +gboolean nm_platform_link_infiniband_get_properties (NMPlatform *self, int ifindex, int *parent, int *p_key, const char **mode); + +gboolean nm_platform_link_veth_get_properties (NMPlatform *self, int ifindex, int *out_peer_ifindex); +gboolean nm_platform_link_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *properties); + +gboolean nm_platform_link_tun_get_properties_ifname (NMPlatform *platform, const char *ifname, NMPlatformTunProperties *props); gboolean nm_platform_wifi_get_capabilities (NMPlatform *self, int ifindex, NMDeviceWifiCapabilities *caps); gboolean nm_platform_wifi_get_bssid (NMPlatform *self, int ifindex, guint8 *bssid); -GByteArray *nm_platform_wifi_get_ssid (NMPlatform *self, int ifindex); guint32 nm_platform_wifi_get_frequency (NMPlatform *self, int ifindex); int nm_platform_wifi_get_quality (NMPlatform *self, int ifindex); guint32 nm_platform_wifi_get_rate (NMPlatform *self, int ifindex); NM80211Mode nm_platform_wifi_get_mode (NMPlatform *self, int ifindex); void nm_platform_wifi_set_mode (NMPlatform *self, int ifindex, NM80211Mode mode); +void nm_platform_wifi_set_powersave (NMPlatform *self, int ifindex, guint32 powersave); guint32 nm_platform_wifi_find_frequency (NMPlatform *self, int ifindex, const guint32 *freqs); void nm_platform_wifi_indicate_addressing_running (NMPlatform *self, int ifindex, gboolean running); @@ -697,17 +814,52 @@ guint32 nm_platform_mesh_get_channel (NMPlatform *self, int ifindex); gboolean nm_platform_mesh_set_channel (NMPlatform *self, int ifindex, guint32 channel); gboolean nm_platform_mesh_set_ssid (NMPlatform *self, int ifindex, const guint8 *ssid, gsize len); -const NMPlatformIP4Address *nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, int plen); +void nm_platform_ip4_address_set_addr (NMPlatformIP4Address *addr, in_addr_t address, int plen); +const struct in6_addr *nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr); + +const NMPlatformIP4Address *nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, int plen, in_addr_t peer_address); + +NMPlatformError nm_platform_link_gre_add (NMPlatform *self, + const char *name, + const NMPlatformLnkGre *props, + const NMPlatformLink **out_link); +NMPlatformError nm_platform_link_ip6tnl_add (NMPlatform *self, + const char *name, + const NMPlatformLnkIp6Tnl *props, + const NMPlatformLink **out_link); +NMPlatformError nm_platform_link_ipip_add (NMPlatform *self, + const char *name, + const NMPlatformLnkIpIp *props, + const NMPlatformLink **out_link); +NMPlatformError nm_platform_link_macvlan_add (NMPlatform *self, + const char *name, + int parent, + const NMPlatformLnkMacvlan *props, + const NMPlatformLink **out_link); +NMPlatformError nm_platform_link_sit_add (NMPlatform *self, + const char *name, + const NMPlatformLnkSit *props, + const NMPlatformLink **out_link); + const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address, int plen); GArray *nm_platform_ip4_address_get_all (NMPlatform *self, int ifindex); GArray *nm_platform_ip6_address_get_all (NMPlatform *self, int ifindex); -gboolean nm_platform_ip4_address_add (NMPlatform *self, int ifindex, - in_addr_t address, in_addr_t peer_address, int plen, - guint32 lifetime, guint32 preferred_lft, +gboolean nm_platform_ip4_address_add (NMPlatform *self, + int ifindex, + in_addr_t address, + int plen, + in_addr_t peer_address, + guint32 lifetime, + guint32 preferred_lft, const char *label); -gboolean nm_platform_ip6_address_add (NMPlatform *self, int ifindex, - struct in6_addr address, struct in6_addr peer_address, int plen, - guint32 lifetime, guint32 preferred_lft, guint flags); +gboolean nm_platform_ip6_address_add (NMPlatform *self, + int ifindex, + struct in6_addr address, + int plen, + struct in6_addr peer_address, + guint32 lifetime, + guint32 preferred_lft, + guint flags); gboolean nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_t address, int plen, in_addr_t peer_address); gboolean nm_platform_ip6_address_delete (NMPlatform *self, int ifindex, struct in6_addr address, int plen); gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, GPtrArray **out_added_addresses); @@ -720,31 +872,54 @@ GArray *nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatform GArray *nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags); gboolean nm_platform_ip4_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source, in_addr_t network, int plen, in_addr_t gateway, - guint32 pref_src, guint32 metric, guint32 mss); + in_addr_t pref_src, guint32 metric, guint32 mss); gboolean nm_platform_ip6_route_add (NMPlatform *self, int ifindex, NMIPConfigSource source, struct in6_addr network, int plen, struct in6_addr gateway, guint32 metric, guint32 mss); gboolean nm_platform_ip4_route_delete (NMPlatform *self, int ifindex, in_addr_t network, int plen, guint32 metric); gboolean nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6_addr network, int plen, guint32 metric); -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); +const char *nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len); +const char *nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len); +const char *nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *buf, gsize len); +const char *nm_platform_lnk_ip6tnl_to_string (const NMPlatformLnkIp6Tnl *lnk, char *buf, gsize len); +const char *nm_platform_lnk_ipip_to_string (const NMPlatformLnkIpIp *lnk, char *buf, gsize len); +const char *nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len); +const char *nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len); +const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len); +const char *nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len); +const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len); +const char *nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *buf, gsize len); +const char *nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsize len); +const char *nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len); + +const char *nm_platform_vlan_qos_mapping_to_string (const char *name, + const NMVlanQosMapping *map, + gsize n_map, + char *buf, + gsize len); int nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b); +int nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b); +int nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b); +int nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6Tnl *b); +int nm_platform_lnk_ipip_cmp (const NMPlatformLnkIpIp *a, const NMPlatformLnkIpIp *b); +int nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b); +int nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b); +int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b); +int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *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_libnl_link_netnsid (void); gboolean nm_platform_check_support_kernel_extended_ifa_flags (NMPlatform *self); gboolean nm_platform_check_support_user_ipv6ll (NMPlatform *self); -void nm_platform_addr_flags2str (int flags, char *buf, size_t size); +const char *nm_platform_link_flags2str (unsigned flags, char *buf, gsize len); +const char *nm_platform_link_inet6_addrgenmode2str (guint8 mode, char *buf, gsize len); +const char *nm_platform_addr_flags2str (unsigned flags, char *buf, gsize len); +const char *nm_platform_route_scope2str (int scope, char *buf, gsize len); int nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPlatformIPAddress *b); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index eb6bfc3a..892fd9dd 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -22,11 +22,11 @@ #include +#include "nm-default.h" #include "nmp-object.h" #include "nm-platform-utils.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" -#include "nm-logging.h" /*********************************************************************************************/ @@ -82,6 +82,42 @@ _id_hash_ip6_addr (const struct in6_addr *addr) return hash; } +static int +_vlan_xgress_qos_mappings_cmp (guint n_map, + const NMVlanQosMapping *map1, + const NMVlanQosMapping *map2) +{ + guint i; + + for (i = 0; i < n_map; i++) { + if (map1[i].from != map2[i].from) + return map1[i].from < map2[i].from ? -1 : 1; + if (map1[i].to != map2[i].to) + return map1[i].to < map2[i].to ? -1 : 1; + } + return 0; +} + +static void +_vlan_xgress_qos_mappings_cpy (guint *dst_n_map, + const NMVlanQosMapping **dst_map, + guint src_n_map, + const NMVlanQosMapping *src_map) +{ + if (src_n_map == 0) { + g_clear_pointer (dst_map, g_free); + *dst_n_map = 0; + } else if ( src_n_map != *dst_n_map + || _vlan_xgress_qos_mappings_cmp (src_n_map, *dst_map, src_map) != 0) { + g_clear_pointer (dst_map, g_free); + *dst_n_map = src_n_map; + if (src_n_map > 0) + *dst_map = g_memdup (src_map, sizeof (*src_map) * src_n_map); + } +} + +/******************************************************************/ + static const char * _link_get_driver (GUdevDevice *udev_device, const char *kind, const char *ifname) { @@ -207,6 +243,14 @@ static void _vt_cmd_obj_dispose_link (NMPObject *obj) { g_clear_object (&obj->_link.udev.device); + nmp_object_unref (obj->_link.netlink.lnk); +} + +static void +_vt_cmd_obj_dispose_lnk_vlan (NMPObject *obj) +{ + g_free ((gpointer) obj->_lnk_vlan.ingress_qos_map); + g_free ((gpointer) obj->_lnk_vlan.egress_qos_map); } static NMPObject * @@ -274,10 +318,16 @@ nmp_object_stackinit (NMPObject *obj, NMPObjectType obj_type, const NMPlatformOb const NMPObject * nmp_object_stackinit_id (NMPObject *obj, const NMPObject *src) { + const NMPClass *klass; + nm_assert (NMP_OBJECT_IS_VALID (src)); nm_assert (obj); - NMP_OBJECT_GET_CLASS (src)->cmd_obj_stackinit_id (obj, src); + klass = NMP_OBJECT_GET_CLASS (src); + if (!klass->cmd_obj_stackinit_id) + nmp_object_stackinit (obj, klass->obj_type, NULL); + else + klass->cmd_obj_stackinit_id (obj, src); return obj; } @@ -296,19 +346,20 @@ _vt_cmd_obj_stackinit_id_link (NMPObject *obj, const NMPObject *src) } const NMPObject * -nmp_object_stackinit_id_ip4_address (NMPObject *obj, int ifindex, guint32 address, int plen) +nmp_object_stackinit_id_ip4_address (NMPObject *obj, int ifindex, guint32 address, int plen, guint32 peer_address) { nmp_object_stackinit (obj, NMP_OBJECT_TYPE_IP4_ADDRESS, NULL); obj->ip4_address.ifindex = ifindex; obj->ip4_address.address = address; obj->ip4_address.plen = plen; + obj->ip4_address.peer_address = peer_address; return obj; } static void _vt_cmd_obj_stackinit_id_ip4_address (NMPObject *obj, const NMPObject *src) { - nmp_object_stackinit_id_ip4_address (obj, src->ip_address.ifindex, src->ip4_address.address, src->ip_address.plen); + nmp_object_stackinit_id_ip4_address (obj, src->ip_address.ifindex, src->ip4_address.address, src->ip_address.plen, src->ip4_address.peer_address); } const NMPObject * @@ -369,50 +420,131 @@ const char * nmp_object_to_string (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size) { const NMPClass *klass; - char buf2[sizeof (_nm_platform_to_string_buffer)]; - char buf3[sizeof (_nm_platform_to_string_buffer)]; - const char *str; - - if (!buf) { - buf = _nm_platform_to_string_buffer; - buf_size = sizeof (_nm_platform_to_string_buffer); - } + char buf2[sizeof (_nm_utils_to_string_buffer)]; - if (!obj) { - g_strlcpy (buf, "NULL", buf_size); + if (!nm_utils_to_string_buffer_init_null (obj, &buf, &buf_size)) return buf; - } g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj), NULL); klass = NMP_OBJECT_GET_CLASS (obj); + if (klass->cmd_obj_to_string) + return klass->cmd_obj_to_string (obj, to_string_mode, buf, buf_size); + switch (to_string_mode) { case NMP_OBJECT_TO_STRING_ID: + if (!klass->cmd_plobj_to_string_id) { + g_snprintf (buf, buf_size, "%p", obj); + return buf; + } return klass->cmd_plobj_to_string_id (&obj->object, buf, buf_size); case NMP_OBJECT_TO_STRING_ALL: - g_strlcpy (buf2, NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object), sizeof (buf2)); + g_snprintf (buf, buf_size, + "[%s,%p,%d,%ccache,%calive,%cvisible; %s]", + klass->obj_type_name, obj, obj->_ref_count, + obj->is_cached ? '+' : '-', + nmp_object_is_alive (obj) ? '+' : '-', + nmp_object_is_visible (obj) ? '+' : '-', + NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf2, sizeof (buf2))); + return buf; + case NMP_OBJECT_TO_STRING_PUBLIC: + NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf, buf_size); + return buf; + default: + g_return_val_if_reached ("ERROR"); + } +} - if (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LINK) { - g_snprintf (buf3, sizeof (buf3), - ",%cin-nl,%p", - obj->_link.netlink.is_in_netlink ? '+' : '-', - obj->_link.udev.device); +static const char * +_vt_cmd_obj_to_string_link (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size) +{ + const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj); + char buf2[sizeof (_nm_utils_to_string_buffer)]; + char buf3[sizeof (_nm_utils_to_string_buffer)]; + + switch (to_string_mode) { + case NMP_OBJECT_TO_STRING_ID: + return klass->cmd_plobj_to_string_id (&obj->object, buf, buf_size); + case NMP_OBJECT_TO_STRING_ALL: + g_snprintf (buf, buf_size, + "[%s,%p,%d,%ccache,%calive,%cvisible,%cin-nl,%p; %s]", + klass->obj_type_name, obj, obj->_ref_count, + obj->is_cached ? '+' : '-', + nmp_object_is_alive (obj) ? '+' : '-', + nmp_object_is_visible (obj) ? '+' : '-', + obj->_link.netlink.is_in_netlink ? '+' : '-', + obj->_link.udev.device, + nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof (buf2))); + return buf; + case NMP_OBJECT_TO_STRING_PUBLIC: + if (obj->_link.netlink.lnk) { + NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf2, sizeof (buf2)); + nmp_object_to_string (obj->_link.netlink.lnk, NMP_OBJECT_TO_STRING_PUBLIC, buf3, sizeof (buf3)); + g_snprintf (buf, buf_size, + "%s; %s", + buf2, buf3); } else - buf3[0] = '\0'; + NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf, buf_size); + return buf; + default: + g_return_val_if_reached ("ERROR"); + } +} + +static const char * +_vt_cmd_obj_to_string_lnk_vlan (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size) +{ + const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj); + char buf2[sizeof (_nm_utils_to_string_buffer)]; + char *b; + gsize l; + + klass = NMP_OBJECT_GET_CLASS (obj); + + switch (to_string_mode) { + case NMP_OBJECT_TO_STRING_ID: + g_snprintf (buf, buf_size, "%p", obj); + return buf; + case NMP_OBJECT_TO_STRING_ALL: g_snprintf (buf, buf_size, - "[%s,%p,%d,%ccache,%calive,%cvisible%s; %s]", + "[%s,%p,%d,%ccache,%calive,%cvisible; %s]", klass->obj_type_name, obj, obj->_ref_count, obj->is_cached ? '+' : '-', nmp_object_is_alive (obj) ? '+' : '-', nmp_object_is_visible (obj) ? '+' : '-', - buf3, buf2); + nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof (buf2))); return buf; case NMP_OBJECT_TO_STRING_PUBLIC: - str = NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object); - if (str != buf) - g_strlcpy (buf, str, buf_size); + NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf, buf_size); + + b = buf; + l = strlen (b); + b += l; + buf_size -= l; + + if (obj->_lnk_vlan.n_ingress_qos_map) { + nm_platform_vlan_qos_mapping_to_string (" ingress-qos-map", + obj->_lnk_vlan.ingress_qos_map, + obj->_lnk_vlan.n_ingress_qos_map, + b, + buf_size); + l = strlen (b); + b += l; + buf_size -= l; + } + if (obj->_lnk_vlan.n_egress_qos_map) { + nm_platform_vlan_qos_mapping_to_string (" egress-qos-map", + obj->_lnk_vlan.egress_qos_map, + obj->_lnk_vlan.n_egress_qos_map, + b, + buf_size); + l = strlen (b); + b += l; + buf_size -= l; + } + return buf; default: g_return_val_if_reached ("ERROR"); @@ -425,21 +557,27 @@ _vt_cmd_plobj_to_string_id_##type (const NMPlatformObject *_obj, char *buf, gsiz { \ plat_type *const obj = (plat_type *) _obj; \ char buf1[NM_UTILS_INET_ADDRSTRLEN]; \ + char buf2[NM_UTILS_INET_ADDRSTRLEN]; \ \ (void) buf1; \ + (void) buf2; \ g_snprintf (buf, buf_len, \ __VA_ARGS__); \ return buf; \ } -_vt_cmd_plobj_to_string_id (link, NMPlatformLink, "%d", obj->ifindex); -_vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d", obj->ifindex, nm_utils_inet4_ntop ( obj->address, buf1), obj->plen); -_vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s/%d", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1), obj->plen); -_vt_cmd_plobj_to_string_id (ip4_route, NMPlatformIP4Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet4_ntop ( obj->network, buf1), obj->plen, obj->metric); -_vt_cmd_plobj_to_string_id (ip6_route, NMPlatformIP6Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet6_ntop (&obj->network, buf1), obj->plen, obj->metric); +_vt_cmd_plobj_to_string_id (link, NMPlatformLink, "%d", obj->ifindex); +_vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d%s%s", obj->ifindex, nm_utils_inet4_ntop ( obj->address, buf1), obj->plen, + obj->peer_address != obj->address ? "," : "", + obj->peer_address != obj->address ? nm_utils_inet4_ntop (obj->peer_address & nm_utils_ip4_prefix_to_netmask (obj->plen), buf2) : ""); +_vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1)); +_vt_cmd_plobj_to_string_id (ip4_route, NMPlatformIP4Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet4_ntop ( obj->network, buf1), obj->plen, obj->metric); +_vt_cmd_plobj_to_string_id (ip6_route, NMPlatformIP6Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet6_ntop (&obj->network, buf1), obj->plen, obj->metric); int nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2) { + const NMPClass *klass1, *klass2; + if (obj1 == obj2) return 0; if (!obj1) @@ -450,49 +588,72 @@ nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2) g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj1), -1); g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj2), 1); - if (NMP_OBJECT_GET_CLASS (obj1) != NMP_OBJECT_GET_CLASS (obj2)) - return NMP_OBJECT_GET_CLASS (obj1) < NMP_OBJECT_GET_CLASS (obj2) ? -1 : 1; + klass1 = NMP_OBJECT_GET_CLASS (obj1); + klass2 = NMP_OBJECT_GET_CLASS (obj2); + + if (klass1 != klass2) + return klass1->obj_type < klass2->obj_type ? -1 : 1; - return NMP_OBJECT_GET_CLASS (obj1)->cmd_plobj_cmp (&obj1->object, &obj2->object); + if (klass1->cmd_obj_cmp) + return klass1->cmd_obj_cmp (obj1, obj2); + return klass1->cmd_plobj_cmp (&obj1->object, &obj2->object); } -gboolean -nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2) +static int +_vt_cmd_obj_cmp_link (const NMPObject *obj1, const NMPObject *obj2) { - const NMPClass *klass; + int i; - g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj1), FALSE); - g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj2), FALSE); + i = nm_platform_link_cmp (&obj1->link, &obj2->link); + if (i) + return i; + if (obj1->_link.netlink.is_in_netlink != obj2->_link.netlink.is_in_netlink) + return obj1->_link.netlink.is_in_netlink ? -1 : 1; + i = nmp_object_cmp (obj1->_link.netlink.lnk, obj2->_link.netlink.lnk); + if (i) + return i; + if (obj1->_link.udev.device != obj2->_link.udev.device) { + if (!obj1->_link.udev.device) + return -1; + if (!obj2->_link.udev.device) + return 1; + + /* Only compare based on pointer values. That is ugly because it's not a + * stable sort order, but probably udev gives us always the same GUdevDevice + * instance. + * + * Have this check as very last. */ + return (obj1->_link.udev.device < obj2->_link.udev.device) ? -1 : 1; + } + return 0; +} - if (obj1 == obj2) - return TRUE; +static int +_vt_cmd_obj_cmp_lnk_vlan (const NMPObject *obj1, const NMPObject *obj2) +{ + int c; - klass = NMP_OBJECT_GET_CLASS (obj1); + c = nm_platform_lnk_vlan_cmp (&obj1->lnk_vlan, &obj2->lnk_vlan); + if (c) + return c; - if (klass != NMP_OBJECT_GET_CLASS (obj2)) - return FALSE; + if (obj1->_lnk_vlan.n_ingress_qos_map != obj2->_lnk_vlan.n_ingress_qos_map) + return obj1->_lnk_vlan.n_ingress_qos_map < obj2->_lnk_vlan.n_ingress_qos_map ? -1 : 1; + if (obj1->_lnk_vlan.n_egress_qos_map != obj2->_lnk_vlan.n_egress_qos_map) + return obj1->_lnk_vlan.n_egress_qos_map < obj2->_lnk_vlan.n_egress_qos_map ? -1 : 1; - return klass->cmd_obj_equal (obj1, obj2); -} + c = _vlan_xgress_qos_mappings_cmp (obj1->_lnk_vlan.n_ingress_qos_map, obj1->_lnk_vlan.ingress_qos_map, obj2->_lnk_vlan.ingress_qos_map); + if (c) + return c; + c = _vlan_xgress_qos_mappings_cmp (obj1->_lnk_vlan.n_egress_qos_map, obj1->_lnk_vlan.egress_qos_map, obj2->_lnk_vlan.egress_qos_map); -static gboolean -_vt_cmd_obj_equal_plain (const NMPObject *obj1, const NMPObject *obj2) -{ - return NMP_OBJECT_GET_CLASS (obj1)->cmd_plobj_cmp (&obj1->object, &obj2->object) == 0; + return c; } -static gboolean -_vt_cmd_obj_equal_link (const NMPObject *obj1, const NMPObject *obj2) +gboolean +nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2) { - const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj1); - - if (klass->cmd_plobj_cmp (&obj1->object, &obj2->object) != 0) - return FALSE; - if (obj1->_link.netlink.is_in_netlink != obj2->_link.netlink.is_in_netlink) - return FALSE; - if (obj1->_link.udev.device != obj2->_link.udev.device) - return FALSE; - return TRUE; + return nmp_object_cmp (obj1, obj2) == 0; } /* @src is a const object, which is not entirely correct for link types, where @@ -511,11 +672,46 @@ nmp_object_copy (NMPObject *dst, const NMPObject *src, gboolean id_only) g_return_if_fail (klass == NMP_OBJECT_GET_CLASS (src)); - if (id_only) - klass->cmd_plobj_id_copy (&dst->object, &src->object); - else + if (id_only) { + if (klass->cmd_plobj_id_copy) + klass->cmd_plobj_id_copy (&dst->object, &src->object); + } else if (klass->cmd_obj_copy) klass->cmd_obj_copy (dst, src); + else + memcpy (&dst->object, &src->object, klass->sizeof_data); + } +} + +static void +_vt_cmd_obj_copy_link (NMPObject *dst, const NMPObject *src) +{ + if (dst->_link.udev.device != src->_link.udev.device) { + if (src->_link.udev.device) + g_object_ref (src->_link.udev.device); + if (dst->_link.udev.device) + g_object_unref (dst->_link.udev.device); } + if (dst->_link.netlink.lnk != src->_link.netlink.lnk) { + if (src->_link.netlink.lnk) + nmp_object_ref (src->_link.netlink.lnk); + if (dst->_link.netlink.lnk) + nmp_object_unref (dst->_link.netlink.lnk); + } + dst->_link = src->_link; +} + +static void +_vt_cmd_obj_copy_lnk_vlan (NMPObject *dst, const NMPObject *src) +{ + dst->lnk_vlan = src->lnk_vlan; + _vlan_xgress_qos_mappings_cpy (&dst->_lnk_vlan.n_ingress_qos_map, + &dst->_lnk_vlan.ingress_qos_map, + src->_lnk_vlan.n_ingress_qos_map, + src->_lnk_vlan.ingress_qos_map); + _vlan_xgress_qos_mappings_cpy (&dst->_lnk_vlan.n_egress_qos_map, + &dst->_lnk_vlan.egress_qos_map, + src->_lnk_vlan.n_egress_qos_map, + src->_lnk_vlan.egress_qos_map); } #define _vt_cmd_plobj_id_copy(type, plat_type, cmd) \ @@ -533,10 +729,10 @@ _vt_cmd_plobj_id_copy (ip4_address, NMPlatformIP4Address, { dst->ifindex = src->ifindex; dst->plen = src->plen; dst->address = src->address; + dst->peer_address = src->peer_address; }); _vt_cmd_plobj_id_copy (ip6_address, NMPlatformIP6Address, { dst->ifindex = src->ifindex; - dst->plen = src->plen; dst->address = src->address; }); _vt_cmd_plobj_id_copy (ip4_route, NMPlatformIP4Route, { @@ -552,24 +748,6 @@ _vt_cmd_plobj_id_copy (ip6_route, NMPlatformIP6Route, { dst->network = src->network; }); -static void -_vt_cmd_obj_copy_plain (NMPObject *dst, const NMPObject *src) -{ - memcpy (&dst->object, &src->object, NMP_OBJECT_GET_CLASS (dst)->sizeof_data); -} - -static void -_vt_cmd_obj_copy_link (NMPObject *dst, const NMPObject *src) -{ - if (dst->_link.udev.device != src->_link.udev.device) { - if (dst->_link.udev.device) - g_object_unref (dst->_link.udev.device); - if (src->_link.udev.device) - g_object_ref (src->_link.udev.device); - } - dst->_link = src->_link; -} - /* Uses internally nmp_object_copy(), hence it also violates the const * promise for @obj. * */ @@ -603,6 +781,7 @@ nmp_object_id_equal (const NMPObject *obj1, const NMPObject *obj2) klass = NMP_OBJECT_GET_CLASS (obj1); return klass == NMP_OBJECT_GET_CLASS (obj2) + && klass->cmd_plobj_id_equal && klass->cmd_plobj_id_equal (&obj1->object, &obj2->object); } @@ -619,10 +798,13 @@ _vt_cmd_plobj_id_equal (link, NMPlatformLink, _vt_cmd_plobj_id_equal (ip4_address, NMPlatformIP4Address, obj1->ifindex == obj2->ifindex && obj1->plen == obj2->plen - && obj1->address == obj2->address); + && obj1->address == obj2->address + /* for IPv4 addresses, you can add the same local address with differing peer-adddress + * (IFA_ADDRESS), provided that their net-part differs. */ + && ((obj1->peer_address ^ obj2->peer_address) & nm_utils_ip4_prefix_to_netmask (obj1->plen)) == 0); _vt_cmd_plobj_id_equal (ip6_address, NMPlatformIP6Address, obj1->ifindex == obj2->ifindex - && obj1->plen == obj2->plen + /* for IPv6 addresses, the prefix length is not part of the primary identifier. */ && IN6_ARE_ADDR_EQUAL (&obj1->address, &obj2->address)); _vt_cmd_plobj_id_equal (ip4_route, NMPlatformIP4Route, obj1->ifindex == obj2->ifindex @@ -638,11 +820,20 @@ _vt_cmd_plobj_id_equal (ip6_route, NMPlatformIP6Route, guint nmp_object_id_hash (const NMPObject *obj) { + const NMPClass *klass; + if (!obj) return 0; g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj), 0); - return NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_id_hash (&obj->object); + + klass = NMP_OBJECT_GET_CLASS (obj); + + if (klass->cmd_plobj_id_hash) + return klass->cmd_plobj_id_hash (&obj->object); + + /* unhashable objects implement pointer equality. */ + return g_direct_hash (obj); } #define _vt_cmd_plobj_id_hash(type, plat_type, cmd) \ @@ -655,34 +846,25 @@ _vt_cmd_plobj_id_hash_##type (const NMPlatformObject *_obj) \ return hash; \ } _vt_cmd_plobj_id_hash (link, NMPlatformLink, { - /* libnl considers: - * .oo_id_attrs = LINK_ATTR_IFINDEX | LINK_ATTR_FAMILY, - */ hash = (guint) 3982791431u; hash = hash + ((guint) obj->ifindex); }) _vt_cmd_plobj_id_hash (ip4_address, NMPlatformIP4Address, { - /* libnl considers: - * .oo_id_attrs = (ADDR_ATTR_FAMILY | ADDR_ATTR_IFINDEX | - * ADDR_ATTR_LOCAL | ADDR_ATTR_PREFIXLEN), - */ hash = (guint) 3591309853u; hash = hash + ((guint) obj->ifindex); hash = hash * 33 + ((guint) obj->plen); hash = hash * 33 + ((guint) obj->address); + + /* for IPv4 we must also consider the net-part of the peer-address (IFA_ADDRESS) */ + hash = hash * 33 + ((guint) (obj->peer_address & nm_utils_ip4_prefix_to_netmask (obj->plen))); }) _vt_cmd_plobj_id_hash (ip6_address, NMPlatformIP6Address, { hash = (guint) 2907861637u; hash = hash + ((guint) obj->ifindex); - hash = hash * 33 + ((guint) obj->plen); + /* for IPv6 addresses, the prefix length is not part of the primary identifier. */ hash = hash * 33 + _id_hash_ip6_addr (&obj->address); }) _vt_cmd_plobj_id_hash (ip4_route, NMPlatformIP4Route, { - /* libnl considers: - * .oo_id_attrs = (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS | - * ROUTE_ATTR_TABLE | ROUTE_ATTR_DST | - * ROUTE_ATTR_PRIO), - */ hash = (guint) 2569857221u; hash = hash + ((guint) obj->ifindex); hash = hash * 33 + ((guint) obj->plen); @@ -700,11 +882,15 @@ _vt_cmd_plobj_id_hash (ip6_route, NMPlatformIP6Route, { gboolean nmp_object_is_alive (const NMPObject *obj) { + const NMPClass *klass; + /* for convenience, allow NULL. */ if (!obj) return FALSE; - return NMP_OBJECT_GET_CLASS (obj)->cmd_obj_is_alive (obj); + klass = NMP_OBJECT_GET_CLASS (obj); + return !klass->cmd_obj_is_alive + || klass->cmd_obj_is_alive (obj); } static gboolean @@ -742,75 +928,29 @@ _vt_cmd_obj_is_alive_ipx_route (const NMPObject *obj) gboolean nmp_object_is_visible (const NMPObject *obj) - { + const NMPClass *klass; + /* for convenience, allow NULL. */ if (!obj) return FALSE; - return NMP_OBJECT_GET_CLASS (obj)->cmd_obj_is_visible (obj); -} + klass = NMP_OBJECT_GET_CLASS (obj); -static gboolean -_vt_cmd_obj_is_visible_link (const NMPObject *obj) -{ - return obj->object.ifindex > 0 - && obj->_link.netlink.is_in_netlink - && obj->link.name[0]; -} + /* a dead object is never visible. */ + if ( klass->cmd_obj_is_alive + && !klass->cmd_obj_is_alive (obj)) + return FALSE; -static gboolean -_vt_cmd_obj_is_visible_ipx_address (const NMPObject *obj) -{ - return obj->object.ifindex > 0; + return !klass->cmd_obj_is_visible + || klass->cmd_obj_is_visible (obj); } static gboolean -_vt_cmd_obj_is_visible_ipx_route (const NMPObject *obj) -{ - NMIPConfigSource source = obj->ip_route.source; - - return obj->object.ifindex > 0 && source != _NM_IP_CONFIG_SOURCE_RTM_F_CLONED; -} - -/******************************************************************/ - -/** - * nmp_object_from_nl: - * @platform: platform instance (needed to lookup sysctl) - * @nlo: - * @id_only: if %TRUE, only fill the id fields of the object and leave the - * other fields unset. This is useful to create a needle to lookup a matching - * item in the cache. - * @complete_from_cache: sometimes the netlink object doesn't contain all information. - * If true, look them up in the cache and preserve the original value. - * - * Convert a libnl object to a platform object. - * Returns: a NMPObject containing @nlo. If @id_only is %TRUE, only the id fields - * are defined. - **/ -NMPObject * -nmp_object_from_nl (NMPlatform *platform, const struct nl_object *nlo, gboolean id_only, gboolean complete_from_cache) -{ - NMPObjectType obj_type = _nlo_get_object_type (nlo); - NMPObject *obj; - - if (obj_type == NMP_OBJECT_TYPE_UNKNOWN) - return NULL; - - obj = nmp_object_new (obj_type, NULL); - - if (!NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_init_from_nl (platform, &obj->object, nlo, id_only, complete_from_cache)) { - nmp_object_unref (obj); - return NULL; - } - return obj; -} - -struct nl_object * -nmp_object_to_nl (NMPlatform *platform, const NMPObject *obj, gboolean id_only) +_vt_cmd_obj_is_visible_link (const NMPObject *obj) { - return NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_nl (platform, &obj->object, id_only); + return obj->_link.netlink.is_in_netlink + && obj->link.name[0]; } /******************************************************************/ @@ -922,6 +1062,24 @@ nmp_cache_id_init_routes_visible (NMPCacheId *id, return id; } +NMPCacheId * +nmp_cache_id_init_link_by_ifname (NMPCacheId *id, + const char *ifname) +{ + gsize l; + + _nmp_cache_id_init (id, NMP_CACHE_ID_TYPE_LINK_BY_IFNAME); + + if ( !ifname + || (l = strlen (ifname)) > sizeof (id->link_by_ifname.ifname_short)) + g_return_val_if_reached (id); + + /* the trailing NUL is dropped!! */ + memcpy (id->link_by_ifname.ifname_short, ifname, l); + + return id; +} + /******************************************************************/ static gboolean @@ -940,14 +1098,26 @@ _nmp_object_init_cache_id (const NMPObject *obj, NMPCacheIdType id_type, NMPCach *out_id = NULL; return TRUE; default: - return klass->cmd_obj_init_cache_id (obj, id_type, id, out_id); + return klass->cmd_obj_init_cache_id + && klass->cmd_obj_init_cache_id (obj, id_type, id, out_id); } } static gboolean _vt_cmd_obj_init_cache_id_link (const NMPObject *obj, NMPCacheIdType id_type, NMPCacheId *id, const NMPCacheId **out_id) { - return FALSE; + switch (id_type) { + case NMP_CACHE_ID_TYPE_LINK_BY_IFNAME: + if (obj->link.name[0]) { + *out_id = nmp_cache_id_init_link_by_ifname (id, obj->link.name); + return TRUE; + } + break; + default: + return FALSE; + } + *out_id = NULL; + return TRUE; } static gboolean @@ -955,7 +1125,7 @@ _vt_cmd_obj_init_cache_id_ipx_address (const NMPObject *obj, NMPCacheIdType id_t { switch (id_type) { case NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX: - if (_vt_cmd_obj_is_visible_ipx_address (obj)) { + if (nmp_object_is_visible (obj)) { nm_assert (obj->object.ifindex > 0); *out_id = nmp_cache_id_init_addrroute_visible_by_ifindex (id, NMP_OBJECT_GET_TYPE (obj), obj->object.ifindex); return TRUE; @@ -973,14 +1143,14 @@ _vt_cmd_obj_init_cache_id_ipx_route (const NMPObject *obj, NMPCacheIdType id_typ { switch (id_type) { case NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX: - if (_vt_cmd_obj_is_visible_ipx_route (obj)) { + if (nmp_object_is_visible (obj)) { nm_assert (obj->object.ifindex > 0); *out_id = nmp_cache_id_init_addrroute_visible_by_ifindex (id, NMP_OBJECT_GET_TYPE (obj), obj->object.ifindex); return TRUE; } break; case NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT: - if ( _vt_cmd_obj_is_visible_ipx_route (obj) + if ( nmp_object_is_visible (obj) && !NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj->ip_route)) { nm_assert (obj->object.ifindex > 0); *out_id = nmp_cache_id_init_routes_visible (id, NMP_OBJECT_GET_TYPE (obj), FALSE, TRUE, 0); @@ -988,7 +1158,7 @@ _vt_cmd_obj_init_cache_id_ipx_route (const NMPObject *obj, NMPCacheIdType id_typ } break; case NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT: - if ( _vt_cmd_obj_is_visible_ipx_route (obj) + if ( nmp_object_is_visible (obj) && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj->ip_route)) { nm_assert (obj->object.ifindex > 0); *out_id = nmp_cache_id_init_routes_visible (id, NMP_OBJECT_GET_TYPE (obj), TRUE, FALSE, 0); @@ -996,7 +1166,7 @@ _vt_cmd_obj_init_cache_id_ipx_route (const NMPObject *obj, NMPCacheIdType id_typ } break; case NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_NO_DEFAULT: - if ( _vt_cmd_obj_is_visible_ipx_route (obj) + if ( nmp_object_is_visible (obj) && !NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj->ip_route)) { nm_assert (obj->object.ifindex > 0); *out_id = nmp_cache_id_init_routes_visible (id, NMP_OBJECT_GET_TYPE (obj), FALSE, TRUE, obj->object.ifindex); @@ -1004,7 +1174,7 @@ _vt_cmd_obj_init_cache_id_ipx_route (const NMPObject *obj, NMPCacheIdType id_typ } break; case NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_ONLY_DEFAULT: - if ( _vt_cmd_obj_is_visible_ipx_route (obj) + if ( nmp_object_is_visible (obj) && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj->ip_route)) { nm_assert (obj->object.ifindex > 0); *out_id = nmp_cache_id_init_routes_visible (id, NMP_OBJECT_GET_TYPE (obj), TRUE, FALSE, obj->object.ifindex); @@ -1211,7 +1381,7 @@ nmp_cache_lookup_link_full (const NMPCache *cache, const NMPObject *obj; const NMPlatformObject *const *list; guint i, len; - NMPCacheId cache_id; + NMPCacheId cache_id, *p_cache_id; if (ifindex > 0) { obj = nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&obj_needle, ifindex)); @@ -1226,7 +1396,14 @@ nmp_cache_lookup_link_full (const NMPCache *cache, } else if (!ifname && !match_fn) return NULL; else { - list = nmp_cache_lookup_multi (cache, nmp_cache_id_init_object_type (&cache_id, NMP_OBJECT_TYPE_LINK, visible_only), &len); + if ( ifname + && strlen (ifname) <= sizeof (cache_id.link_by_ifname.ifname_short)) { + p_cache_id = nmp_cache_id_init_link_by_ifname (&cache_id, ifname); + ifname = NULL; + } else + p_cache_id = nmp_cache_id_init_object_type (&cache_id, NMP_OBJECT_TYPE_LINK, visible_only); + + list = nmp_cache_lookup_multi (cache, p_cache_id, &len); for (i = 0; i < len; i++) { obj = NMP_OBJECT_UP_CAST (list[i]); @@ -1303,12 +1480,8 @@ _nmp_cache_update_add (NMPCache *cache, NMPObject *obj) nm_assert (!obj->is_cached); nmp_object_ref (obj); nm_assert (!nm_multi_index_lookup_first_by_value (cache->idx_multi, &obj->object)); -#if GLIB_CHECK_VERSION(2, 40, 0) - if (!g_hash_table_add (cache->idx_main, obj)) + if (!nm_g_hash_table_add (cache->idx_main, obj)) g_assert_not_reached (); -#else - g_hash_table_add (cache->idx_main, obj); -#endif obj->is_cached = TRUE; _nmp_cache_update_cache (cache, obj, FALSE); } @@ -1385,7 +1558,7 @@ nmp_cache_remove_netlink (NMPCache *cache, const NMPObject *obj_needle, NMPObjec { if (NMP_OBJECT_GET_TYPE (obj_needle) == NMP_OBJECT_TYPE_LINK) { NMPObject *old; - auto_nmp_obj NMPObject *obj = NULL; + nm_auto_nmpobj NMPObject *obj = NULL; /* For nmp_cache_remove_netlink() we have an incomplete @obj_needle instance to be * removed from netlink. Link objects are alive without being in netlink when they @@ -1510,8 +1683,8 @@ nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, * We could add efficient reverse lookup by adding a reverse index to NMMultiIndex. But that * also adds some cost to support an (uncommon?) usage pattern. * - * Instead we just don't support it. Actually, we expect the user to - * create a new instance with nmp_object_from_nl(). That is what nmp_cache_update_netlink(). + * Instead we just don't support it, instead we expect the user to + * create a new instance from netlink. * * TL;DR: a cached object must never be modified. */ @@ -1580,7 +1753,7 @@ NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache, int ifindex, GUdevDevice *udev_device, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data) { NMPObject *old; - auto_nmp_obj NMPObject *obj = NULL; + nm_auto_nmpobj NMPObject *obj = NULL; old = (NMPObject *) nmp_cache_lookup_link (cache, ifindex); @@ -1647,7 +1820,7 @@ NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache, int ifindex, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data) { NMPObject *old; - auto_nmp_obj NMPObject *obj = NULL; + nm_auto_nmpobj NMPObject *obj = NULL; old = (NMPObject *) nmp_cache_lookup_link (cache, ifindex); @@ -1727,7 +1900,7 @@ nmp_cache_free (NMPCache *cache) void ASSERT_nmp_cache_is_consistent (const NMPCache *cache) { -#ifdef NM_MORE_ASSERTS +#if NM_MORE_ASSERTS NMMultiIndexIter iter_multi; GHashTableIter iter_hash; guint i, len; @@ -1788,24 +1961,23 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .sizeof_data = sizeof (NMPObjectLink), .sizeof_public = sizeof (NMPlatformLink), .obj_type_name = "link", - .nl_type = "route/link", .addr_family = AF_UNSPEC, .rtm_gettype = RTM_GETLINK, + .signal_type_id = NM_PLATFORM_SIGNAL_ID_LINK, .signal_type = NM_PLATFORM_SIGNAL_LINK_CHANGED, .cmd_obj_init_cache_id = _vt_cmd_obj_init_cache_id_link, - .cmd_obj_equal = _vt_cmd_obj_equal_link, + .cmd_obj_cmp = _vt_cmd_obj_cmp_link, .cmd_obj_copy = _vt_cmd_obj_copy_link, .cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_link, .cmd_obj_dispose = _vt_cmd_obj_dispose_link, .cmd_obj_is_alive = _vt_cmd_obj_is_alive_link, .cmd_obj_is_visible = _vt_cmd_obj_is_visible_link, - .cmd_plobj_init_from_nl = _nmp_vt_cmd_plobj_init_from_nl_link, - .cmd_plobj_to_nl = _nmp_vt_cmd_plobj_to_nl_link, + .cmd_obj_to_string = _vt_cmd_obj_to_string_link, .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_link, .cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_link, .cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_link, .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_link, - .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj)) nm_platform_link_to_string, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_link_to_string, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_link_cmp, }, [NMP_OBJECT_TYPE_IP4_ADDRESS - 1] = { @@ -1813,23 +1985,18 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .sizeof_data = sizeof (NMPObjectIP4Address), .sizeof_public = sizeof (NMPlatformIP4Address), .obj_type_name = "ip4-address", - .nl_type = "route/addr", .addr_family = AF_INET, .rtm_gettype = RTM_GETADDR, + .signal_type_id = NM_PLATFORM_SIGNAL_ID_IP4_ADDRESS, .signal_type = NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, .cmd_obj_init_cache_id = _vt_cmd_obj_init_cache_id_ipx_address, - .cmd_obj_equal = _vt_cmd_obj_equal_plain, - .cmd_obj_copy = _vt_cmd_obj_copy_plain, .cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip4_address, .cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_address, - .cmd_obj_is_visible = _vt_cmd_obj_is_visible_ipx_address, - .cmd_plobj_init_from_nl = _nmp_vt_cmd_plobj_init_from_nl_ip4_address, - .cmd_plobj_to_nl = _nmp_vt_cmd_plobj_to_nl_ip4_address, .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip4_address, .cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_ip4_address, .cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip4_address, .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip4_address, - .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj)) nm_platform_ip4_address_to_string, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip4_address_to_string, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip4_address_cmp, }, [NMP_OBJECT_TYPE_IP6_ADDRESS - 1] = { @@ -1837,23 +2004,18 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .sizeof_data = sizeof (NMPObjectIP6Address), .sizeof_public = sizeof (NMPlatformIP6Address), .obj_type_name = "ip6-address", - .nl_type = "route/addr", .addr_family = AF_INET6, .rtm_gettype = RTM_GETADDR, + .signal_type_id = NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS, .signal_type = NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, .cmd_obj_init_cache_id = _vt_cmd_obj_init_cache_id_ipx_address, - .cmd_obj_equal = _vt_cmd_obj_equal_plain, - .cmd_obj_copy = _vt_cmd_obj_copy_plain, .cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip6_address, .cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_address, - .cmd_obj_is_visible = _vt_cmd_obj_is_visible_ipx_address, - .cmd_plobj_init_from_nl = _nmp_vt_cmd_plobj_init_from_nl_ip6_address, - .cmd_plobj_to_nl = _nmp_vt_cmd_plobj_to_nl_ip6_address, .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_address, .cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_ip6_address, .cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip6_address, .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip6_address, - .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj)) nm_platform_ip6_address_to_string, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip6_address_to_string, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_address_cmp }, [NMP_OBJECT_TYPE_IP4_ROUTE - 1] = { @@ -1861,23 +2023,18 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .sizeof_data = sizeof (NMPObjectIP4Route), .sizeof_public = sizeof (NMPlatformIP4Route), .obj_type_name = "ip4-route", - .nl_type = "route/route", .addr_family = AF_INET, .rtm_gettype = RTM_GETROUTE, + .signal_type_id = NM_PLATFORM_SIGNAL_ID_IP4_ROUTE, .signal_type = NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, .cmd_obj_init_cache_id = _vt_cmd_obj_init_cache_id_ipx_route, - .cmd_obj_equal = _vt_cmd_obj_equal_plain, - .cmd_obj_copy = _vt_cmd_obj_copy_plain, .cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip4_route, .cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route, - .cmd_obj_is_visible = _vt_cmd_obj_is_visible_ipx_route, - .cmd_plobj_init_from_nl = _nmp_vt_cmd_plobj_init_from_nl_ip4_route, - .cmd_plobj_to_nl = _nmp_vt_cmd_plobj_to_nl_ip4_route, .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip4_route, .cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_ip4_route, .cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip4_route, .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip4_route, - .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj)) nm_platform_ip4_route_to_string, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip4_route_to_string, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip4_route_cmp, }, [NMP_OBJECT_TYPE_IP6_ROUTE - 1] = { @@ -1885,24 +2042,104 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .sizeof_data = sizeof (NMPObjectIP6Route), .sizeof_public = sizeof (NMPlatformIP6Route), .obj_type_name = "ip6-route", - .nl_type = "route/route", .addr_family = AF_INET6, .rtm_gettype = RTM_GETROUTE, + .signal_type_id = NM_PLATFORM_SIGNAL_ID_IP6_ROUTE, .signal_type = NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, .cmd_obj_init_cache_id = _vt_cmd_obj_init_cache_id_ipx_route, - .cmd_obj_equal = _vt_cmd_obj_equal_plain, - .cmd_obj_copy = _vt_cmd_obj_copy_plain, .cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip6_route, .cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route, - .cmd_obj_is_visible = _vt_cmd_obj_is_visible_ipx_route, - .cmd_plobj_init_from_nl = _nmp_vt_cmd_plobj_init_from_nl_ip6_route, - .cmd_plobj_to_nl = _nmp_vt_cmd_plobj_to_nl_ip6_route, .cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_route, .cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_ip6_route, .cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip6_route, .cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip6_route, - .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj)) nm_platform_ip6_route_to_string, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip6_route_to_string, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_route_cmp, }, + [NMP_OBJECT_TYPE_LNK_GRE - 1] = { + .obj_type = NMP_OBJECT_TYPE_LNK_GRE, + .sizeof_data = sizeof (NMPObjectLnkGre), + .sizeof_public = sizeof (NMPlatformLnkGre), + .obj_type_name = "gre", + .lnk_link_type = NM_LINK_TYPE_GRE, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_gre_to_string, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_gre_cmp, + }, + [NMP_OBJECT_TYPE_LNK_INFINIBAND - 1] = { + .obj_type = NMP_OBJECT_TYPE_LNK_INFINIBAND, + .sizeof_data = sizeof (NMPObjectLnkInfiniband), + .sizeof_public = sizeof (NMPlatformLnkInfiniband), + .obj_type_name = "infiniband", + .lnk_link_type = NM_LINK_TYPE_INFINIBAND, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_infiniband_to_string, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_infiniband_cmp, + }, + [NMP_OBJECT_TYPE_LNK_IP6TNL - 1] = { + .obj_type = NMP_OBJECT_TYPE_LNK_IP6TNL, + .sizeof_data = sizeof (NMPObjectLnkIp6Tnl), + .sizeof_public = sizeof (NMPlatformLnkIp6Tnl), + .obj_type_name = "ip6tnl", + .lnk_link_type = NM_LINK_TYPE_IP6TNL, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ip6tnl_to_string, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp, + }, + [NMP_OBJECT_TYPE_LNK_IPIP - 1] = { + .obj_type = NMP_OBJECT_TYPE_LNK_IPIP, + .sizeof_data = sizeof (NMPObjectLnkIpIp), + .sizeof_public = sizeof (NMPlatformLnkIpIp), + .obj_type_name = "ipip", + .lnk_link_type = NM_LINK_TYPE_IPIP, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ipip_to_string, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ipip_cmp, + }, + [NMP_OBJECT_TYPE_LNK_MACVLAN - 1] = { + .obj_type = NMP_OBJECT_TYPE_LNK_MACVLAN, + .sizeof_data = sizeof (NMPObjectLnkMacvlan), + .sizeof_public = sizeof (NMPlatformLnkMacvlan), + .obj_type_name = "macvlan", + .lnk_link_type = NM_LINK_TYPE_MACVLAN, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_macvlan_to_string, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macvlan_cmp, + }, + [NMP_OBJECT_TYPE_LNK_MACVTAP - 1] = { + .obj_type = NMP_OBJECT_TYPE_LNK_MACVTAP, + .sizeof_data = sizeof (NMPObjectLnkMacvtap), + .sizeof_public = sizeof (NMPlatformLnkMacvtap), + .obj_type_name = "macvtap", + .lnk_link_type = NM_LINK_TYPE_MACVTAP, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_macvlan_to_string, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macvlan_cmp, + }, + [NMP_OBJECT_TYPE_LNK_SIT - 1] = { + .obj_type = NMP_OBJECT_TYPE_LNK_SIT, + .sizeof_data = sizeof (NMPObjectLnkSit), + .sizeof_public = sizeof (NMPlatformLnkSit), + .obj_type_name = "sit", + .lnk_link_type = NM_LINK_TYPE_SIT, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_sit_to_string, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_sit_cmp, + }, + [NMP_OBJECT_TYPE_LNK_VLAN - 1] = { + .obj_type = NMP_OBJECT_TYPE_LNK_VLAN, + .sizeof_data = sizeof (NMPObjectLnkVlan), + .sizeof_public = sizeof (NMPlatformLnkVlan), + .obj_type_name = "vlan", + .lnk_link_type = NM_LINK_TYPE_VLAN, + .cmd_obj_cmp = _vt_cmd_obj_cmp_lnk_vlan, + .cmd_obj_copy = _vt_cmd_obj_copy_lnk_vlan, + .cmd_obj_dispose = _vt_cmd_obj_dispose_lnk_vlan, + .cmd_obj_to_string = _vt_cmd_obj_to_string_lnk_vlan, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_vlan_to_string, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vlan_cmp, + }, + [NMP_OBJECT_TYPE_LNK_VXLAN - 1] = { + .obj_type = NMP_OBJECT_TYPE_LNK_VXLAN, + .sizeof_data = sizeof (NMPObjectLnkVxlan), + .sizeof_public = sizeof (NMPlatformLnkVxlan), + .obj_type_name = "vxlan", + .lnk_link_type = NM_LINK_TYPE_VXLAN, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_vxlan_to_string, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vxlan_cmp, + }, }; diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 5b1887b8..ab1cc2fe 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -64,6 +64,9 @@ typedef enum { /*< skip >*/ /* all the objects of a certain type */ NMP_CACHE_ID_TYPE_OBJECT_TYPE, + /* index for the link objects by ifname. */ + NMP_CACHE_ID_TYPE_LINK_BY_IFNAME, + /* all the visible objects of a certain type */ NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY, @@ -104,6 +107,11 @@ typedef struct { guint8 obj_type; /* NMPObjectType as guint8 */ int ifindex; } object_type_by_ifindex; + struct { + /* NMP_CACHE_ID_TYPE_LINK_BY_IFNAME */ + guint8 _id_type; + char ifname_short[IFNAMSIZ - 1]; /* don't include the trailing NUL so the struct fits in 4 bytes. */ + } link_by_ifname; }; } NMPCacheId; @@ -116,29 +124,31 @@ typedef struct { int rtm_gettype; int sizeof_data; int sizeof_public; + NMPlatformSignalIdType signal_type_id; const char *obj_type_name; - const char *nl_type; const char *signal_type; + /* Only for NMPObjectLnk* types. */ + NMLinkType lnk_link_type; + /* returns %FALSE, if the obj type would never have an entry for index type @id_type. If @obj has an index, * initialize @id and set @out_id to it. Otherwise, @out_id is NULL. */ gboolean (*cmd_obj_init_cache_id) (const NMPObject *obj, NMPCacheIdType id_type, NMPCacheId *id, const NMPCacheId **out_id); - gboolean (*cmd_obj_equal) (const NMPObject *obj1, const NMPObject *obj2); + int (*cmd_obj_cmp) (const NMPObject *obj1, const NMPObject *obj2); void (*cmd_obj_copy) (NMPObject *dst, const NMPObject *src); void (*cmd_obj_stackinit_id) (NMPObject *obj, const NMPObject *src); void (*cmd_obj_dispose) (NMPObject *obj); gboolean (*cmd_obj_is_alive) (const NMPObject *obj); gboolean (*cmd_obj_is_visible) (const NMPObject *obj); + const char *(*cmd_obj_to_string) (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size); /* functions that operate on NMPlatformObject */ - gboolean (*cmd_plobj_init_from_nl) (NMPlatform *platform, NMPlatformObject *obj, const struct nl_object *nlo, gboolean id_only, gboolean complete_from_cache); - struct nl_object *(*cmd_plobj_to_nl) (NMPlatform *platform, const NMPlatformObject *obj, gboolean id_only); void (*cmd_plobj_id_copy) (NMPlatformObject *dst, const NMPlatformObject *src); gboolean (*cmd_plobj_id_equal) (const NMPlatformObject *obj1, const NMPlatformObject *obj2); guint (*cmd_plobj_id_hash) (const NMPlatformObject *obj); const char *(*cmd_plobj_to_string_id) (const NMPlatformObject *obj, char *buf, gsize buf_size); - const char *(*cmd_plobj_to_string) (const NMPlatformObject *obj); + const char *(*cmd_plobj_to_string) (const NMPlatformObject *obj, char *buf, gsize len); int (*cmd_plobj_cmp) (const NMPlatformObject *obj1, const NMPlatformObject *obj2); } NMPClass; @@ -148,7 +158,10 @@ typedef struct { NMPlatformLink _public; struct { - guint8 is_in_netlink; + bool is_in_netlink; + + /* Additional data that depends on the link-type (IFLA_INFO_DATA) */ + NMPObject *lnk; } netlink; struct { @@ -156,6 +169,45 @@ typedef struct { } udev; } NMPObjectLink; +typedef struct { + NMPlatformLnkGre _public; +} NMPObjectLnkGre; + +typedef struct { + NMPlatformLnkInfiniband _public; +} NMPObjectLnkInfiniband; + +typedef struct { + NMPlatformLnkIp6Tnl _public; +} NMPObjectLnkIp6Tnl; + +typedef struct { + NMPlatformLnkIpIp _public; +} NMPObjectLnkIpIp; + +typedef struct { + NMPlatformLnkMacvlan _public; +} NMPObjectLnkMacvlan; + +typedef NMPObjectLnkMacvlan NMPObjectLnkMacvtap; + +typedef struct { + NMPlatformLnkSit _public; +} NMPObjectLnkSit; + +typedef struct { + NMPlatformLnkVlan _public; + + guint n_ingress_qos_map; + guint n_egress_qos_map; + const NMVlanQosMapping *ingress_qos_map; + const NMVlanQosMapping *egress_qos_map; +} NMPObjectLnkVlan; + +typedef struct { + NMPlatformLnkVxlan _public; +} NMPObjectLnkVxlan; + typedef struct { NMPlatformIP4Address _public; } NMPObjectIP4Address; @@ -175,13 +227,37 @@ typedef struct { struct _NMPObject { const NMPClass *_class; int _ref_count; - guint8 is_cached; + bool is_cached; union { NMPlatformObject object; NMPlatformLink link; NMPObjectLink _link; + NMPlatformLnkGre lnk_gre; + NMPObjectLnkGre _lnk_gre; + + NMPlatformLnkInfiniband lnk_infiniband; + NMPObjectLnkInfiniband _lnk_infiniband; + + NMPlatformLnkIpIp lnk_ipip; + NMPObjectLnkIpIp _lnk_ipip; + + NMPlatformLnkIp6Tnl lnk_ip6tnl; + NMPObjectLnkIp6Tnl _lnk_ip6tnl; + + NMPlatformLnkMacvlan lnk_macvlan; + NMPObjectLnkMacvlan _lnk_macvlan; + + NMPlatformLnkSit lnk_sit; + NMPObjectLnkSit _lnk_sit; + + NMPlatformLnkVlan lnk_vlan; + NMPObjectLnkVlan _lnk_vlan; + + NMPlatformLnkVxlan lnk_vxlan; + NMPObjectLnkVxlan _lnk_vxlan; + NMPlatformIPAddress ip_address; NMPlatformIPXAddress ipx_address; NMPlatformIP4Address ip4_address; @@ -269,7 +345,7 @@ NMPObject *nmp_object_new_link (int ifindex); const NMPObject *nmp_object_stackinit (NMPObject *obj, NMPObjectType obj_type, const NMPlatformObject *plobj); const NMPObject *nmp_object_stackinit_id (NMPObject *obj, const NMPObject *src); const NMPObject *nmp_object_stackinit_id_link (NMPObject *obj, int ifindex); -const NMPObject *nmp_object_stackinit_id_ip4_address (NMPObject *obj, int ifindex, guint32 address, int plen); +const NMPObject *nmp_object_stackinit_id_ip4_address (NMPObject *obj, int ifindex, guint32 address, int plen, guint32 peer_address); const NMPObject *nmp_object_stackinit_id_ip6_address (NMPObject *obj, int ifindex, const struct in6_addr *address, int plen); const NMPObject *nmp_object_stackinit_id_ip4_route (NMPObject *obj, int ifindex, guint32 network, int plen, guint32 metric); const NMPObject *nmp_object_stackinit_id_ip6_route (NMPObject *obj, int ifindex, const struct in6_addr *network, int plen, guint32 metric); @@ -286,9 +362,9 @@ gboolean nmp_object_is_visible (const NMPObject *obj); void _nmp_object_fixup_link_udev_fields (NMPObject *obj, gboolean use_udev); -#define auto_nmp_obj __attribute__((cleanup(_nmp_auto_obj_cleanup))) +#define nm_auto_nmpobj __attribute__((cleanup(_nm_auto_nmpobj_cleanup))) static inline void -_nmp_auto_obj_cleanup (NMPObject **pobj) +_nm_auto_nmpobj_cleanup (NMPObject **pobj) { nmp_object_unref (*pobj); } @@ -306,6 +382,7 @@ void nmp_cache_id_destroy (NMPCacheId *id); NMPCacheId *nmp_cache_id_init_object_type (NMPCacheId *id, NMPObjectType obj_type, gboolean visible_only); NMPCacheId *nmp_cache_id_init_addrroute_visible_by_ifindex (NMPCacheId *id, NMPObjectType obj_type, int ifindex); NMPCacheId *nmp_cache_id_init_routes_visible (NMPCacheId *id, NMPObjectType obj_type, gboolean with_default, gboolean with_non_default, int ifindex); +NMPCacheId *nmp_cache_id_init_link_by_ifname (NMPCacheId *id, const char *ifname); const NMPlatformObject *const *nmp_cache_lookup_multi (const NMPCache *cache, const NMPCacheId *cache_id, guint *out_len); GArray *nmp_cache_lookup_multi_to_array (const NMPCache *cache, NMPObjectType obj_type, const NMPCacheId *cache_id); @@ -341,21 +418,4 @@ NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache, int ifi NMPCache *nmp_cache_new (void); void nmp_cache_free (NMPCache *cache); -NMPObject *nmp_object_from_nl (NMPlatform *platform, const struct nl_object *nlo, gboolean id_only, gboolean complete_from_cache); -struct nl_object *nmp_object_to_nl (NMPlatform *platform, const NMPObject *obj, gboolean id_only); - -/* the following functions are currently implemented inside nm-linux-platform, because - * they depend on utility functions there. */ -NMPObjectType _nlo_get_object_type (const struct nl_object *nlo); -gboolean _nmp_vt_cmd_plobj_init_from_nl_link (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache); -gboolean _nmp_vt_cmd_plobj_init_from_nl_ip4_address (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache); -gboolean _nmp_vt_cmd_plobj_init_from_nl_ip6_address (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache); -gboolean _nmp_vt_cmd_plobj_init_from_nl_ip4_route (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache); -gboolean _nmp_vt_cmd_plobj_init_from_nl_ip6_route (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache); -struct nl_object *_nmp_vt_cmd_plobj_to_nl_link (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only); -struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip4_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only); -struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip6_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only); -struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip4_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only); -struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip6_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only); - #endif /* __NMP_OBJECT_H__ */ diff --git a/src/platform/tests/Makefile.am b/src/platform/tests/Makefile.am index 085f56ca..b097fcf6 100644 --- a/src/platform/tests/Makefile.am +++ b/src/platform/tests/Makefile.am @@ -1,14 +1,14 @@ AM_CPPFLAGS = \ -I${top_srcdir} \ - -I${top_srcdir}/include \ - -I${top_builddir}/include \ + -I${top_srcdir}/shared \ + -I${top_builddir}/shared \ -I${top_srcdir}/src \ -I${top_builddir}/src \ -I${top_srcdir}/libnm-core \ -I${top_builddir}/libnm-core \ -I${srcdir}/.. \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ $(GUDEV_CFLAGS) \ diff --git a/src/platform/tests/Makefile.in b/src/platform/tests/Makefile.in index e21a3bb6..c04d6a1b 100644 --- a/src/platform/tests/Makefile.in +++ b/src/platform/tests/Makefile.in @@ -503,7 +503,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -515,8 +514,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -526,6 +523,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -580,16 +578,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -626,6 +621,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -654,7 +651,6 @@ 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@ @@ -669,6 +665,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -729,6 +727,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -736,6 +735,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -751,12 +751,12 @@ 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 \ +AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/shared \ + -I${top_builddir}/shared -I${top_srcdir}/src \ -I${top_builddir}/src -I${top_srcdir}/libnm-core \ -I${top_builddir}/libnm-core -I${srcdir}/.. \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE $(GLIB_CFLAGS) \ $(GUDEV_CFLAGS) $(LIBNL_CFLAGS) $(am__append_1) PLATFORM_SOURCES = \ diff --git a/src/platform/tests/monitor.c b/src/platform/tests/monitor.c index f1058db8..5cc3114c 100644 --- a/src/platform/tests/monitor.c +++ b/src/platform/tests/monitor.c @@ -3,34 +3,66 @@ #include #include +#include "nm-default.h" #include "nm-linux-platform.h" -#include "nm-logging.h" #include "nm-test-utils.h" NMTST_DEFINE (); +static struct { + gboolean persist; +} global_opt = { + .persist = TRUE, +}; + +static gboolean +read_argv (int *argc, char ***argv) +{ + GOptionContext *context; + GOptionEntry options[] = { + { "no-persist", 'P', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &global_opt.persist, "Exit after processing netlink messages", NULL }, + { 0 }, + }; + gs_free_error GError *error = NULL; + + context = g_option_context_new (NULL); + g_option_context_set_summary (context, "Monitor netlink events in NMPlatform."); + g_option_context_add_main_entries (context, options, NULL); + + if (!g_option_context_parse (context, argc, argv, &error)) { + g_warning ("Error parsing command line arguments: %s", error->message); + g_option_context_free (context); + return FALSE; + } + + g_option_context_free (context); + return TRUE; +} + int main (int argc, char **argv) { GMainLoop *loop; -#if !GLIB_CHECK_VERSION (2, 35, 0) - g_type_init (); -#endif - if (!g_getenv ("G_MESSAGES_DEBUG")) g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); nmtst_init_with_logging (&argc, &argv, "DEBUG", "ALL"); + if (!read_argv (&argc, &argv)) + return 2; + nm_log_info (LOGD_PLATFORM, "platform monitor start"); loop = g_main_loop_new (NULL, FALSE); nm_linux_platform_setup (); - g_main_loop_run (loop); + if (global_opt.persist) + g_main_loop_run (loop); + + g_main_loop_unref (loop); return EXIT_SUCCESS; } diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c index d6f346b3..566bb479 100644 --- a/src/platform/tests/test-address.c +++ b/src/platform/tests/test-address.c @@ -4,12 +4,19 @@ #define DEVICE_NAME "nm-test-device" #define IP4_ADDRESS "192.0.2.1" +#define IP4_ADDRESS_PEER "192.0.2.2" +#define IP4_ADDRESS_PEER2 "192.0.3.1" #define IP4_PLEN 24 #define IP6_ADDRESS "2001:db8:a:b:1:2:3:4" #define IP6_PLEN 64 +static int DEVICE_IFINDEX = -1; +static int EX = -1; + +/*****************************************************************************/ + static void -ip4_address_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformIP4Address *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data) +ip4_address_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformIP4Address *received, NMPlatformSignalChangeType change_type, SignalData *data) { g_assert (received); g_assert_cmpint (received->ifindex, ==, ifindex); @@ -25,11 +32,11 @@ ip4_address_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, g_main_loop_quit (data->loop); data->received_count++; - debug ("Received signal '%s' %dth time.", data->name, data->received_count); + _LOGD ("Received signal '%s' %dth time.", data->name, data->received_count); } static void -ip6_address_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformIP6Address *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data) +ip6_address_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformIP6Address *received, NMPlatformSignalChangeType change_type, SignalData *data) { g_assert (received); g_assert_cmpint (received->ifindex, ==, ifindex); @@ -45,13 +52,15 @@ ip6_address_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, g_main_loop_quit (data->loop); data->received_count++; - debug ("Received signal '%s' %dth time.", data->name, data->received_count); + _LOGD ("Received signal '%s' %dth time.", data->name, data->received_count); } +/*****************************************************************************/ + static void -test_ip4_address (void) +test_ip4_address_general (void) { - int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + const int ifindex = DEVICE_IFINDEX; 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); @@ -64,13 +73,13 @@ test_ip4_address (void) inet_pton (AF_INET, IP4_ADDRESS, &addr); /* Add address */ - g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); - g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL)); - g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); + g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, NULL); + g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); accept_signal (address_added); /* Add address again (aka update) */ - g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL)); + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime + 100, preferred + 50, NULL); accept_signals (address_changed, 0, 1); /* Test address listing */ @@ -80,16 +89,17 @@ test_ip4_address (void) address = &g_array_index (addresses, NMPlatformIP4Address, 0); g_assert_cmpint (address->ifindex, ==, ifindex); g_assert_cmphex (address->address, ==, addr); + g_assert_cmphex (address->peer_address, ==, addr); g_assert_cmpint (address->plen, ==, IP4_PLEN); g_array_unref (addresses); /* Remove address */ - g_assert (nm_platform_ip4_address_delete (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); - g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); + nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, addr); + g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); accept_signal (address_removed); /* Remove address again */ - g_assert (nm_platform_ip4_address_delete (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0)); + nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, addr); free_signal (address_added); free_signal (address_changed); @@ -97,9 +107,9 @@ test_ip4_address (void) } static void -test_ip6_address (void) +test_ip6_address_general (void) { - int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + const int ifindex = DEVICE_IFINDEX; 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); @@ -114,12 +124,12 @@ test_ip6_address (void) /* Add address */ g_assert (!nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); - g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags)); + nmtstp_ip6_address_add (EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags); g_assert (nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); accept_signal (address_added); /* Add address again (aka update) */ - g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags)); + nmtstp_ip6_address_add (EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags); accept_signals (address_changed, 0, 1); /* Test address listing */ @@ -133,12 +143,15 @@ test_ip6_address (void) g_array_unref (addresses); /* Remove address */ - g_assert (nm_platform_ip6_address_delete (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); + nmtstp_ip6_address_del (EX, ifindex, addr, IP6_PLEN); g_assert (!nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); accept_signal (address_removed); /* Remove address again */ - g_assert (nm_platform_ip6_address_delete (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); + nmtstp_ip6_address_del (EX, ifindex, addr, IP6_PLEN); + + /* ensure not pending signal. */ + accept_signals (address_changed, 0, 1); free_signal (address_added); free_signal (address_changed); @@ -146,11 +159,11 @@ test_ip6_address (void) } static void -test_ip4_address_external (void) +test_ip4_address_general_2 (void) { + const int ifindex = DEVICE_IFINDEX; 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 (NM_PLATFORM_GET, DEVICE_NAME); in_addr_t addr; guint32 lifetime = 2000; guint32 preferred = 1000; @@ -161,38 +174,31 @@ test_ip4_address_external (void) /* 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_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME), NULL)); + g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, DEVICE_IFINDEX, NULL)); /* 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_get (NM_PLATFORM_GET, 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_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, NULL); + accept_signal (address_added); + g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); + nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, addr); + accept_signal (address_removed); + g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); /* 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 (NM_PLATFORM_GET, ifindex, addr, 0, IP4_PLEN, lifetime, preferred, NULL)); - g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, NULL); + g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr)); 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, 0)); - g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN)); - accept_signal (address_removed);*/ free_signal (address_added); free_signal (address_removed); } static void -test_ip6_address_external (void) +test_ip6_address_general_2 (void) { + const int ifindex = DEVICE_IFINDEX; 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 (NM_PLATFORM_GET, DEVICE_NAME); struct in6_addr addr; guint32 lifetime = 2000; guint32 preferred = 1000; @@ -201,51 +207,197 @@ test_ip6_address_external (void) 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); + nmtstp_ip6_address_add (EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, 0); + accept_signal (address_added); g_assert (nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); - run_command ("ip address delete %s/%d dev %s", IP6_ADDRESS, IP6_PLEN, DEVICE_NAME); - wait_signal (address_removed); + + nmtstp_ip6_address_del (EX, ifindex, addr, IP6_PLEN); + accept_signal (address_removed); g_assert (!nm_platform_ip6_address_get (NM_PLATFORM_GET, 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 (NM_PLATFORM_GET, ifindex, addr, in6addr_any, IP6_PLEN, lifetime, preferred, flags)); + nmtstp_ip6_address_add (EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, 0); + accept_signal (address_added); g_assert (nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); + + nmtstp_ip6_address_add (EX, ifindex, addr, IP6_PLEN, in6addr_any, lifetime, preferred, flags); + ensure_no_signal (address_added); + g_assert (nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); + + free_signal (address_added); + free_signal (address_removed); +} + +/*****************************************************************************/ + +static void +test_ip4_address_peer (void) +{ + const int ifindex = DEVICE_IFINDEX; + 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); + in_addr_t addr, addr_peer, addr_peer2; + guint32 lifetime = 2000; + guint32 preferred = 1000; + const NMPlatformIP4Address *a; + + inet_pton (AF_INET, IP4_ADDRESS, &addr); + inet_pton (AF_INET, IP4_ADDRESS_PEER, &addr_peer); + inet_pton (AF_INET, IP4_ADDRESS_PEER2, &addr_peer2); + g_assert (ifindex > 0); + + g_assert (addr != addr_peer); + + g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL)); + accept_signals (address_removed, 0, G_MAXINT); + accept_signals (address_added, 0, G_MAXINT); + + /* Add/delete notification */ + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr_peer, lifetime, preferred, NULL); 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 (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); - g_assert (!nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, addr, IP6_PLEN)); - wait_signal (address_removed);*/ + g_assert ((a = nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer))); + g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer2)); + + nmtstp_ip_address_assert_lifetime ((NMPlatformIPAddress *) a, -1, lifetime, preferred); + + nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr_peer2, lifetime, preferred, NULL); + accept_signal (address_added); + g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer)); + g_assert ((a = nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer2))); + + nmtstp_ip_address_assert_lifetime ((NMPlatformIPAddress *) a, -1, lifetime, preferred); + + g_assert (addr != addr_peer); + nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, addr_peer); + accept_signal (address_removed); + g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer)); + g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr_peer2)); free_signal (address_added); free_signal (address_removed); } +/*****************************************************************************/ + +static void +test_ip4_address_peer_zero (void) +{ + const int ifindex = DEVICE_IFINDEX; + in_addr_t addr, addr_peer; + guint32 lifetime = 2000; + guint32 preferred = 1000; + const int plen = 24; + const char *label = NULL; + in_addr_t peers[3], r_peers[3]; + int i; + GArray *addrs; + + g_assert (ifindex > 0); + + inet_pton (AF_INET, "192.168.5.2", &addr); + inet_pton (AF_INET, "192.168.6.2", &addr_peer); + peers[0] = addr; + peers[1] = addr_peer; + peers[2] = 0; + + g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL)); + + nmtst_rand_perm (NULL, r_peers, peers, sizeof (peers[0]), G_N_ELEMENTS (peers)); + for (i = 0; i < G_N_ELEMENTS (peers); i++) { + g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, plen, r_peers[i])); + + nmtstp_ip4_address_add (EX, ifindex, addr, plen, r_peers[i], lifetime, preferred, label); + + addrs = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); + g_assert (addrs); + g_assert_cmpint (addrs->len, ==, i + 1); + g_array_unref (addrs); + } + + if (nmtst_is_debug () && nmtstp_is_root_test ()) + nmtstp_run_command_check ("ip address show dev %s", DEVICE_NAME); + + nmtst_rand_perm (NULL, r_peers, peers, sizeof (peers[0]), G_N_ELEMENTS (peers)); + for (i = 0; i < G_N_ELEMENTS (peers); i++) { + g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, plen, r_peers[i])); + + nmtstp_ip4_address_del (EX, ifindex, addr, plen, r_peers[i]); + + addrs = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); + g_assert (addrs); + g_assert_cmpint (addrs->len, ==, G_N_ELEMENTS (peers) - i - 1); + g_array_unref (addrs); + } +} + +/*****************************************************************************/ + void init_tests (int *argc, char ***argv) { nmtst_init_with_logging (argc, argv, NULL, "ALL"); } -void -setup_tests (void) +/***************************************************************************** + * SETUP TESTS + *****************************************************************************/ + +typedef struct { + const char *testpath; + GTestFunc test_func; +} TestSetup; + +static void +_g_test_run (gconstpointer user_data) { - SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME); + const TestSetup *s = user_data; + int ifindex; + + _LOGT ("TEST: start %s", s->testpath); nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)); g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME)); - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS); - accept_signal (link_added); - free_signal (link_added); + g_assert_cmpint (nm_platform_link_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL), ==, NM_PLATFORM_ERROR_SUCCESS); - g_test_add_func ("/address/internal/ip4", test_ip4_address); - g_test_add_func ("/address/internal/ip6", test_ip6_address); + ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + g_assert_cmpint (ifindex, >, 0); + g_assert_cmpint (DEVICE_IFINDEX, ==, -1); - 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); - } + DEVICE_IFINDEX = ifindex; + EX = nmtstp_run_command_check_external_global (); + + s->test_func (); + + g_assert_cmpint (DEVICE_IFINDEX, ==, ifindex); + DEVICE_IFINDEX = -1; + + g_assert_cmpint (ifindex, ==, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)); + g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex)); + _LOGT ("TEST: finished %s", s->testpath); +} + +static void +_g_test_add_func (const char *testpath, + GTestFunc test_func) +{ + TestSetup *s; + + s = g_new0 (TestSetup, 1); + s->testpath = testpath; + s->test_func = test_func; + + g_test_add_data_func_full (testpath, s, _g_test_run, g_free); +} + +void +setup_tests (void) +{ + _g_test_add_func ("/address/ipv4/general", test_ip4_address_general); + _g_test_add_func ("/address/ipv6/general", test_ip6_address_general); + + _g_test_add_func ("/address/ipv4/general-2", test_ip4_address_general_2); + _g_test_add_func ("/address/ipv6/general-2", test_ip6_address_general_2); + + _g_test_add_func ("/address/ipv4/peer", test_ip4_address_peer); + _g_test_add_func ("/address/ipv4/peer/zero", test_ip4_address_peer_zero); } diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index 0b825114..9e624a02 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -35,7 +35,7 @@ test_cleanup_internal (void) inet_pton (AF_INET6, "2001:db8:e:f:1:2:3:4", &gateway6); /* Create and set up device */ - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS); + g_assert (nm_platform_link_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS); accept_signal (link_added); free_signal (link_added); g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME), NULL)); @@ -43,8 +43,8 @@ test_cleanup_internal (void) g_assert (ifindex > 0); /* Add routes and addresses */ - g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, 0, plen4, lifetime, preferred, NULL)); - g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr6, in6addr_any, plen6, lifetime, preferred, flags)); + g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, plen4, addr4, lifetime, preferred, NULL)); + g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr6, plen6, in6addr_any, lifetime, preferred, flags)); g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss)); g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss)); g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, 0, 0, gateway4, 0, metric, mss)); diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index b0eae63b..09a57f87 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -2,6 +2,8 @@ #include #include +#include +#include #include "test-common.h" @@ -10,9 +12,8 @@ #define SIGNAL_DATA_FMT "'%s-%s' ifindex %d%s%s%s (%d times received)" #define SIGNAL_DATA_ARG(data) (data)->name, nm_platform_signal_change_type_to_string ((data)->change_type), (data)->ifindex, (data)->ifname ? " ifname '" : "", (data)->ifname ? (data)->ifname : "", (data)->ifname ? "'" : "", (data)->received_count - gboolean -nmtst_platform_is_root_test (void) +nmtstp_is_root_test (void) { NM_PRAGMA_WARNING_DISABLE("-Wtautological-compare") return (SETUP == nm_linux_platform_setup); @@ -20,9 +21,9 @@ nmtst_platform_is_root_test (void) } gboolean -nmtst_platform_is_sysfs_writable (void) +nmtstp_is_sysfs_writable (void) { - return !nmtst_platform_is_root_test () + return !nmtstp_is_root_test () || (access ("/sys/devices", W_OK) == 0); } @@ -34,7 +35,7 @@ add_signal_full (const char *name, NMPlatformSignalChangeType change_type, GCall data->name = name; data->change_type = change_type; data->received_count = 0; - data->handler_id = g_signal_connect (nm_platform_get (), name, callback, data); + data->handler_id = g_signal_connect (NM_PLATFORM_GET, name, callback, data); data->ifindex = ifindex; data->ifname = ifname; @@ -46,7 +47,7 @@ add_signal_full (const char *name, NMPlatformSignalChangeType change_type, GCall void _accept_signal (const char *file, int line, const char *func, SignalData *data) { - debug ("NMPlatformSignalAssert: %s:%d, %s(): Accepting signal one time: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data)); + _LOGD ("NMPlatformSignalAssert: %s:%d, %s(): Accepting signal one time: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data)); if (data->received_count != 1) g_error ("NMPlatformSignalAssert: %s:%d, %s(): failure to accept signal one time: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data)); data->received_count = 0; @@ -55,7 +56,7 @@ _accept_signal (const char *file, int line, const char *func, SignalData *data) void _accept_signals (const char *file, int line, const char *func, SignalData *data, int min, int max) { - debug ("NMPlatformSignalAssert: %s:%d, %s(): Accepting signal [%d,%d] times: "SIGNAL_DATA_FMT, file, line, func, min, max, SIGNAL_DATA_ARG (data)); + _LOGD ("NMPlatformSignalAssert: %s:%d, %s(): Accepting signal [%d,%d] times: "SIGNAL_DATA_FMT, file, line, func, min, max, SIGNAL_DATA_ARG (data)); if (data->received_count < min || data->received_count > max) g_error ("NMPlatformSignalAssert: %s:%d, %s(): failure to accept signal [%d,%d] times: "SIGNAL_DATA_FMT, file, line, func, min, max, SIGNAL_DATA_ARG (data)); data->received_count = 0; @@ -64,15 +65,28 @@ _accept_signals (const char *file, int line, const char *func, SignalData *data, void _ensure_no_signal (const char *file, int line, const char *func, SignalData *data) { - debug ("NMPlatformSignalAssert: %s:%d, %s(): Accepting signal 0 times: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data)); + _LOGD ("NMPlatformSignalAssert: %s:%d, %s(): Accepting signal 0 times: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data)); if (data->received_count > 0) g_error ("NMPlatformSignalAssert: %s:%d, %s(): failure to accept signal 0 times: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data)); } +void +_accept_or_wait_signal (const char *file, int line, const char *func, SignalData *data) +{ + _LOGD ("NMPlatformSignalAssert: %s:%d, %s(): accept-or-wait signal: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data)); + if (data->received_count == 0) { + 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 (file, line, func, data); +} + void _wait_signal (const char *file, int line, const char *func, SignalData *data) { - debug ("NMPlatformSignalAssert: %s:%d, %s(): wait signal: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data)); + _LOGD ("NMPlatformSignalAssert: %s:%d, %s(): wait signal: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data)); if (data->received_count) g_error ("NMPlatformSignalAssert: %s:%d, %s(): failure to wait for signal: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data)); @@ -86,16 +100,16 @@ _wait_signal (const char *file, int line, const char *func, SignalData *data) void _free_signal (const char *file, int line, const char *func, SignalData *data) { - debug ("NMPlatformSignalAssert: %s:%d, %s(): free signal: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data)); + _LOGD ("NMPlatformSignalAssert: %s:%d, %s(): free signal: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data)); if (data->received_count != 0) g_error ("NMPlatformSignalAssert: %s:%d, %s(): failure to free non-accepted signal: "SIGNAL_DATA_FMT, file, line, func, SIGNAL_DATA_ARG (data)); - g_signal_handler_disconnect (nm_platform_get (), data->handler_id); + g_signal_handler_disconnect (NM_PLATFORM_GET, data->handler_id); g_free (data); } void -link_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformLink *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data) +link_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformLink *received, NMPlatformSignalChangeType change_type, SignalData *data) { GArray *links; NMPlatformLink *cached; @@ -114,12 +128,12 @@ link_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlat return; if (data->loop) { - debug ("Quitting main loop."); + _LOGD ("Quitting main loop."); g_main_loop_quit (data->loop); } data->received_count++; - debug ("Received signal '%s-%s' ifindex %d ifname '%s' %dth time.", data->name, nm_platform_signal_change_type_to_string (data->change_type), ifindex, received->name, data->received_count); + _LOGD ("Received signal '%s-%s' ifindex %d ifname '%s' %dth time.", data->name, nm_platform_signal_change_type_to_string (data->change_type), ifindex, received->name, data->received_count); if (change_type == NM_PLATFORM_SIGNAL_REMOVED) g_assert (!nm_platform_link_get_name (NM_PLATFORM_GET, ifindex)); @@ -253,21 +267,1176 @@ _assert_ip4_route_exists (const char *file, guint line, const char *func, gboole } } -void -run_command (const char *format, ...) +int +nmtstp_run_command (const char *format, ...) { - char *command; + int result; + gs_free char *command = NULL; 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); + + _LOGD ("Running command: %s", command); + result = system (command); + _LOGD ("Command finished: result=%d", result); + + return result; +} + +/*****************************************************************************/ + +typedef struct { + GMainLoop *loop; + gboolean timeout; + guint id; +} WaitForSignalData; + +static void +_wait_for_signal_cb (NMPlatform *platform, + NMPObjectType obj_type, + int ifindex, + NMPlatformLink *plink, + NMPlatformSignalChangeType change_type, + gpointer user_data) +{ + WaitForSignalData *data = user_data; + + g_main_loop_quit (data->loop); +} + +static gboolean +_wait_for_signal_timeout (gpointer user_data) +{ + WaitForSignalData *data = user_data; + + data->timeout = TRUE; + data->id = 0; + g_main_loop_quit (data->loop); + return G_SOURCE_REMOVE; +} + +gboolean +nmtstp_wait_for_signal (guint timeout_ms) +{ + WaitForSignalData data = { 0 }; + + gulong id_link, id_ip4_address, id_ip6_address, id_ip4_route, id_ip6_route; + + data.loop = g_main_loop_new (NULL, FALSE); + + id_link = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); + id_ip4_address = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); + id_ip6_address = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); + id_ip4_route = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); + id_ip6_route = g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (_wait_for_signal_cb), &data); + + if (timeout_ms != 0) + data.id = g_timeout_add (timeout_ms, _wait_for_signal_timeout, &data); + + g_main_loop_run (data.loop); + + g_assert (nm_clear_g_signal_handler (NM_PLATFORM_GET, &id_link)); + g_assert (nm_clear_g_signal_handler (NM_PLATFORM_GET, &id_ip4_address)); + g_assert (nm_clear_g_signal_handler (NM_PLATFORM_GET, &id_ip6_address)); + g_assert (nm_clear_g_signal_handler (NM_PLATFORM_GET, &id_ip4_route)); + g_assert (nm_clear_g_signal_handler (NM_PLATFORM_GET, &id_ip6_route)); + + if (nm_clear_g_source (&data.id)) + g_assert (timeout_ms != 0 && !data.timeout); + + g_clear_pointer (&data.loop, g_main_loop_unref); + + return !data.timeout; +} + +gboolean +nmtstp_wait_for_signal_until (gint64 until_ms) +{ + gint64 now; + + while (TRUE) { + now = nm_utils_get_monotonic_timestamp_ms (); + + if (until_ms < now) + return FALSE; + + if (nmtstp_wait_for_signal (MAX (1, until_ms - now))) + return TRUE; + } +} + +const NMPlatformLink * +nmtstp_wait_for_link (const char *ifname, NMLinkType expected_link_type, guint timeout_ms) +{ + return nmtstp_wait_for_link_until (ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms); +} + +const NMPlatformLink * +nmtstp_wait_for_link_until (const char *ifname, NMLinkType expected_link_type, gint64 until_ms) +{ + const NMPlatformLink *plink; + gint64 now; + + while (TRUE) { + now = nm_utils_get_monotonic_timestamp_ms (); + + plink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, ifname); + if ( plink + && (expected_link_type == NM_LINK_TYPE_NONE || plink->type == expected_link_type)) + return plink; + + if (until_ms < now) + return NULL; + + nmtstp_wait_for_signal (MAX (1, until_ms - now)); + } +} + +const NMPlatformLink * +nmtstp_assert_wait_for_link (const char *ifname, NMLinkType expected_link_type, guint timeout_ms) +{ + return nmtstp_assert_wait_for_link_until (ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms); +} + +const NMPlatformLink * +nmtstp_assert_wait_for_link_until (const char *ifname, NMLinkType expected_link_type, gint64 until_ms) +{ + const NMPlatformLink *plink; + + plink = nmtstp_wait_for_link_until (ifname, expected_link_type, until_ms); + g_assert (plink); + return plink; +} + +int +nmtstp_run_command_check_external_global (void) +{ + if (!nmtstp_is_root_test ()) + return FALSE; + switch (nmtst_get_rand_int () % 3) { + case 0: + return -1; + case 1: + return FALSE; + default: + return TRUE; + } +} + +gboolean +nmtstp_run_command_check_external (int external_command) +{ + if (external_command != -1) { + g_assert (NM_IN_SET (external_command, FALSE, TRUE)); + g_assert (!external_command || nmtstp_is_root_test ()); + return !!external_command; + } + if (!nmtstp_is_root_test ()) + return FALSE; + return (nmtst_get_rand_int () % 2) == 0; +} + +#define CHECK_LIFETIME_MAX_DIFF 2 + +gboolean +nmtstp_ip_address_check_lifetime (const NMPlatformIPAddress *addr, + gint64 now, + guint32 expected_lifetime, + guint32 expected_preferred) +{ + gint64 offset; + int i; + + g_assert (addr); + + if (now == -1) + now = nm_utils_get_monotonic_timestamp_s (); + g_assert (now > 0); + + g_assert (expected_preferred <= expected_lifetime); + + if ( expected_lifetime == NM_PLATFORM_LIFETIME_PERMANENT + && expected_lifetime == NM_PLATFORM_LIFETIME_PERMANENT) { + return addr->timestamp == 0 + && addr->lifetime == NM_PLATFORM_LIFETIME_PERMANENT + && addr->preferred == NM_PLATFORM_LIFETIME_PERMANENT; + } + + if (addr->timestamp == 0) + return FALSE; + + offset = (gint64) now - addr->timestamp; + + for (i = 0; i < 2; i++) { + guint32 lft = i ? expected_lifetime : expected_preferred; + guint32 adr = i ? addr->lifetime : addr->preferred; + + if (lft == NM_PLATFORM_LIFETIME_PERMANENT) { + if (adr != NM_PLATFORM_LIFETIME_PERMANENT) + return FALSE; + } else { + if ( adr - offset <= lft - CHECK_LIFETIME_MAX_DIFF + || adr - offset >= lft + CHECK_LIFETIME_MAX_DIFF) + return FALSE; + } + } + return TRUE; +} + +void +nmtstp_ip_address_assert_lifetime (const NMPlatformIPAddress *addr, + gint64 now, + guint32 expected_lifetime, + guint32 expected_preferred) +{ + gint64 n = now; + gint64 offset; + int i; + + g_assert (addr); + + if (now == -1) + now = nm_utils_get_monotonic_timestamp_s (); + g_assert (now > 0); + + g_assert (expected_preferred <= expected_lifetime); + + if ( expected_lifetime == NM_PLATFORM_LIFETIME_PERMANENT + && expected_lifetime == NM_PLATFORM_LIFETIME_PERMANENT) { + g_assert_cmpint (addr->timestamp, ==, 0); + g_assert_cmpint (addr->lifetime, ==, NM_PLATFORM_LIFETIME_PERMANENT); + g_assert_cmpint (addr->preferred, ==, NM_PLATFORM_LIFETIME_PERMANENT); + return; + } + + g_assert_cmpint (addr->timestamp, >, 0); + g_assert_cmpint (addr->timestamp, <=, now); + + offset = (gint64) now - addr->timestamp; + g_assert_cmpint (offset, >=, 0); + + for (i = 0; i < 2; i++) { + guint32 lft = i ? expected_lifetime : expected_preferred; + guint32 adr = i ? addr->lifetime : addr->preferred; + + if (lft == NM_PLATFORM_LIFETIME_PERMANENT) + g_assert_cmpint (adr, ==, NM_PLATFORM_LIFETIME_PERMANENT); + else { + g_assert_cmpint (adr, <=, lft); + g_assert_cmpint (offset, <=, adr); + g_assert_cmpint (adr - offset, <=, lft + CHECK_LIFETIME_MAX_DIFF); + g_assert_cmpint (adr - offset, >=, lft - CHECK_LIFETIME_MAX_DIFF); + } + } + + g_assert (nmtstp_ip_address_check_lifetime (addr, n, expected_lifetime, expected_preferred)); +} + +static void +_ip_address_add (gboolean external_command, + gboolean is_v4, + int ifindex, + const NMIPAddr *address, + int plen, + const NMIPAddr *peer_address, + guint32 lifetime, + guint32 preferred, + const char *label, + guint flags) +{ + gint64 end_time; + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + const char *ifname; + gs_free char *s_valid = NULL; + gs_free char *s_preferred = NULL; + gs_free char *s_label = NULL; + char b1[NM_UTILS_INET_ADDRSTRLEN], b2[NM_UTILS_INET_ADDRSTRLEN]; + + ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); + g_assert (ifname); + + if (lifetime != NM_PLATFORM_LIFETIME_PERMANENT) + s_valid = g_strdup_printf (" valid_lft %d", lifetime); + if (preferred != NM_PLATFORM_LIFETIME_PERMANENT) + s_preferred = g_strdup_printf (" preferred_lft %d", preferred); + if (label) + s_label = g_strdup_printf ("%s:%s", ifname, label); + + if (is_v4) { + char s_peer[100]; + + g_assert (flags == 0); + + if ( peer_address->addr4 != address->addr4 + || nmtst_get_rand_int () % 2) { + /* If the peer is the same as the local address, we can omit it. The result should be identical */ + g_snprintf (s_peer, sizeof (s_peer), " peer %s", nm_utils_inet4_ntop (peer_address->addr4, b2)); + } else + s_peer[0] = '\0'; + + nmtstp_run_command_check ("ip address change %s%s/%d dev %s%s%s%s", + nm_utils_inet4_ntop (address->addr4, b1), + s_peer, + plen, + ifname, + s_valid ?: "", + s_preferred ?: "", + s_label ?: ""); + } else { + g_assert (label == NULL); + + /* flags not implemented (yet) */ + g_assert (flags == 0); + nmtstp_run_command_check ("ip address change %s%s%s/%d dev %s%s%s%s", + nm_utils_inet6_ntop (&address->addr6, b1), + !IN6_IS_ADDR_UNSPECIFIED (&peer_address->addr6) ? " peer " : "", + !IN6_IS_ADDR_UNSPECIFIED (&peer_address->addr6) ? nm_utils_inet6_ntop (&peer_address->addr6, b2) : "", + plen, + ifname, + s_valid ?: "", + s_preferred ?: "", + s_label ?: ""); + } + } else { + gboolean success; + + if (is_v4) { + g_assert (flags == 0); + success = nm_platform_ip4_address_add (NM_PLATFORM_GET, + ifindex, + address->addr4, + plen, + peer_address->addr4, + lifetime, + preferred, + label); + } else { + g_assert (label == NULL); + success = nm_platform_ip6_address_add (NM_PLATFORM_GET, + ifindex, + address->addr6, + plen, + peer_address->addr6, + lifetime, + preferred, + flags); + } + g_assert (success); + } + + /* Let's wait until we see the address. */ + end_time = nm_utils_get_monotonic_timestamp_ms () + 250; + do { + + if (external_command) + nm_platform_process_events (NM_PLATFORM_GET); + + /* let's wait until we see the address as we added it. */ + if (is_v4) { + const NMPlatformIP4Address *a; + + g_assert (flags == 0); + a = nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, address->addr4, plen, peer_address->addr4); + if ( a + && a->peer_address == peer_address->addr4 + && nmtstp_ip_address_check_lifetime ((NMPlatformIPAddress*) a, -1, lifetime, preferred) + && strcmp (a->label, label ?: "") == 0) + break; + } else { + const NMPlatformIP6Address *a; + + g_assert (label == NULL); + g_assert (flags == 0); + + a = nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, address->addr6, plen); + if ( a + && !memcmp (nm_platform_ip6_address_get_peer (a), + (IN6_IS_ADDR_UNSPECIFIED (&peer_address->addr6) || IN6_ARE_ADDR_EQUAL (&address->addr6, &peer_address->addr6)) + ? &address->addr6 : &peer_address->addr6, + sizeof (struct in6_addr)) + && nmtstp_ip_address_check_lifetime ((NMPlatformIPAddress*) a, -1, lifetime, preferred)) + break; + } + + /* for internal command, we expect not to reach this line.*/ + g_assert (external_command); + + g_assert (nmtstp_wait_for_signal_until (end_time)); + } while (TRUE); +} + +#define _assert_pllink(success, pllink, name, type) \ + G_STMT_START { \ + const NMPlatformLink *_pllink = (pllink); \ + \ + if ((success)) { \ + g_assert (_pllink); \ + g_assert (_pllink == nmtstp_link_get_typed (_pllink->ifindex, (name), (type))); \ + } else { \ + g_assert (!_pllink); \ + g_assert (!nmtstp_link_get (0, (name))); \ + } \ + } G_STMT_END + +const NMPlatformLink * +nmtstp_link_dummy_add (gboolean external_command, + const char *name) +{ + const NMPlatformLink *pllink = NULL; + gboolean success; + + g_assert (nm_utils_iface_valid_name (name)); + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + success = !nmtstp_run_command ("ip link add %s type dummy", + name); + if (success) + pllink = nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_DUMMY, 100); + } else + success = nm_platform_link_dummy_add (NM_PLATFORM_GET, name, &pllink) == NM_PLATFORM_ERROR_SUCCESS; + + g_assert (success); + _assert_pllink (success, pllink, name, NM_LINK_TYPE_DUMMY); + return pllink; +} + +const NMPlatformLink * +nmtstp_link_gre_add (gboolean external_command, + const char *name, + const NMPlatformLnkGre *lnk) +{ + const NMPlatformLink *pllink = NULL; + gboolean success; + char buffer[INET_ADDRSTRLEN]; + + g_assert (nm_utils_iface_valid_name (name)); + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + gs_free char *dev = NULL; + + if (lnk->parent_ifindex) + dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (NM_PLATFORM_GET, lnk->parent_ifindex)); + + success = !nmtstp_run_command ("ip tunnel add %s mode gre %s local %s remote %s ttl %u tos %02x %s", + name, + dev ? dev : "", + nm_utils_inet4_ntop (lnk->local, NULL), + nm_utils_inet4_ntop (lnk->remote, buffer), + lnk->ttl, + lnk->tos, + lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); + if (success) + pllink = nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_GRE, 100); + } else + success = nm_platform_link_gre_add (NM_PLATFORM_GET, name, lnk, &pllink) == NM_PLATFORM_ERROR_SUCCESS; + + _assert_pllink (success, pllink, name, NM_LINK_TYPE_GRE); + + return pllink; +} + +const NMPlatformLink * +nmtstp_link_ip6tnl_add (gboolean external_command, + const char *name, + const NMPlatformLnkIp6Tnl *lnk) +{ + const NMPlatformLink *pllink = NULL; + gboolean success; + char buffer[INET6_ADDRSTRLEN]; + + g_assert (nm_utils_iface_valid_name (name)); + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + gs_free char *dev = NULL; + const char *mode; + + if (lnk->parent_ifindex) + dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (NM_PLATFORM_GET, lnk->parent_ifindex)); + + switch (lnk->proto) { + case IPPROTO_IPIP: + mode = "ipip6"; + break; + case IPPROTO_IPV6: + mode = "ip6ip6"; + break; + default: + g_assert_not_reached (); + } + + success = !nmtstp_run_command ("ip -6 tunnel add %s mode %s %s local %s remote %s ttl %u tclass %02x encaplimit %u flowlabel %x", + name, + mode, + dev, + nm_utils_inet6_ntop (&lnk->local, NULL), + nm_utils_inet6_ntop (&lnk->remote, buffer), + lnk->ttl, + lnk->tclass, + lnk->encap_limit, + lnk->flow_label); + if (success) + pllink = nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_IP6TNL, 100); + } else + success = nm_platform_link_ip6tnl_add (NM_PLATFORM_GET, name, lnk, &pllink) == NM_PLATFORM_ERROR_SUCCESS; + + _assert_pllink (success, pllink, name, NM_LINK_TYPE_IP6TNL); + + return pllink; +} + +const NMPlatformLink * +nmtstp_link_ipip_add (gboolean external_command, + const char *name, + const NMPlatformLnkIpIp *lnk) +{ + const NMPlatformLink *pllink = NULL; + gboolean success; + char buffer[INET_ADDRSTRLEN]; + + g_assert (nm_utils_iface_valid_name (name)); + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + gs_free char *dev = NULL; + + if (lnk->parent_ifindex) + dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (NM_PLATFORM_GET, lnk->parent_ifindex)); + + success = !nmtstp_run_command ("ip tunnel add %s mode ipip %s local %s remote %s ttl %u tos %02x %s", + name, + dev, + nm_utils_inet4_ntop (lnk->local, NULL), + nm_utils_inet4_ntop (lnk->remote, buffer), + lnk->ttl, + lnk->tos, + lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); + if (success) + pllink = nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_IPIP, 100); + } else + success = nm_platform_link_ipip_add (NM_PLATFORM_GET, name, lnk, &pllink) == NM_PLATFORM_ERROR_SUCCESS; + + _assert_pllink (success, pllink, name, NM_LINK_TYPE_IPIP); + + return pllink; +} + +const NMPlatformLink * +nmtstp_link_macvlan_add (gboolean external_command, + const char *name, + int parent, + const NMPlatformLnkMacvlan *lnk) +{ + const NMPlatformLink *pllink = NULL; + gboolean success; + NMLinkType link_type; + + g_assert (nm_utils_iface_valid_name (name)); + + external_command = nmtstp_run_command_check_external (external_command); + + link_type = lnk->tap ? NM_LINK_TYPE_MACVTAP : NM_LINK_TYPE_MACVLAN; + + if (external_command) { + const char *dev; + char *modes[] = { + [MACVLAN_MODE_BRIDGE] = "bridge", + [MACVLAN_MODE_VEPA] = "vepa", + [MACVLAN_MODE_PRIVATE] = "private", + [MACVLAN_MODE_PASSTHRU] = "passthru", + }; + + dev = nm_platform_link_get_name (NM_PLATFORM_GET, parent); + g_assert (dev); + g_assert_cmpint (lnk->mode, <, G_N_ELEMENTS (modes)); + + success = !nmtstp_run_command ("ip link add name %s link %s type %s mode %s %s", + name, + dev, + lnk->tap ? "macvtap" : "macvlan", + modes[lnk->mode], + lnk->no_promisc ? "nopromisc" : ""); + if (success) + pllink = nmtstp_assert_wait_for_link (name, link_type, 100); + } else + success = nm_platform_link_macvlan_add (NM_PLATFORM_GET, name, parent, lnk, &pllink) == NM_PLATFORM_ERROR_SUCCESS; + + _assert_pllink (success, pllink, name, link_type); + + return pllink; +} + +const NMPlatformLink * +nmtstp_link_sit_add (gboolean external_command, + const char *name, + const NMPlatformLnkSit *lnk) +{ + const NMPlatformLink *pllink = NULL; + gboolean success; + char buffer[INET_ADDRSTRLEN]; + + g_assert (nm_utils_iface_valid_name (name)); + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + const char *dev = ""; + + if (lnk->parent_ifindex) { + const char *parent_name; + + parent_name = nm_platform_link_get_name (NM_PLATFORM_GET, lnk->parent_ifindex); + g_assert (parent_name); + dev = nm_sprintf_bufa (100, " dev %s", parent_name); + } + + success = !nmtstp_run_command ("ip tunnel add %s mode sit%s local %s remote %s ttl %u tos %02x %s", + name, + dev, + nm_utils_inet4_ntop (lnk->local, NULL), + nm_utils_inet4_ntop (lnk->remote, buffer), + lnk->ttl, + lnk->tos, + lnk->path_mtu_discovery ? "pmtudisc" : "nopmtudisc"); + if (success) + pllink = nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_SIT, 100); + } else + success = nm_platform_link_sit_add (NM_PLATFORM_GET, name, lnk, &pllink) == NM_PLATFORM_ERROR_SUCCESS; + + _assert_pllink (success, pllink, name, NM_LINK_TYPE_SIT); + + return pllink; +} + +const NMPlatformLink * +nmtstp_link_vxlan_add (gboolean external_command, + const char *name, + const NMPlatformLnkVxlan *lnk) +{ + const NMPlatformLink *pllink = NULL; + NMPlatformError plerr; + int err; + + g_assert (nm_utils_iface_valid_name (name)); + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + gs_free char *dev = NULL; + gs_free char *local = NULL, *remote = NULL; + + if (lnk->parent_ifindex) + dev = g_strdup_printf ("dev %s", nm_platform_link_get_name (NM_PLATFORM_GET, lnk->parent_ifindex)); + + if (lnk->local) + local = g_strdup_printf ("%s", nm_utils_inet4_ntop (lnk->local, NULL)); + else if (memcmp (&lnk->local6, &in6addr_any, sizeof (in6addr_any))) + local = g_strdup_printf ("%s", nm_utils_inet6_ntop (&lnk->local6, NULL)); + + if (lnk->group) + remote = g_strdup_printf ("%s", nm_utils_inet4_ntop (lnk->group, NULL)); + else if (memcmp (&lnk->group6, &in6addr_any, sizeof (in6addr_any))) + remote = g_strdup_printf ("%s", nm_utils_inet6_ntop (&lnk->group6, NULL)); + + err = nmtstp_run_command ("ip link add %s type vxlan id %u %s local %s group %s ttl %u tos %02x dstport %u srcport %u %u ageing %u", + name, + lnk->id, + dev ? dev : "", + local, + remote, + lnk->ttl, + lnk->tos, + lnk->dst_port, + lnk->src_port_min, lnk->src_port_max, + lnk->ageing); + /* Older versions of iproute2 don't support adding vxlan devices. + * On failure, fallback to using platform code. */ + if (err == 0) + pllink = nmtstp_assert_wait_for_link (name, NM_LINK_TYPE_VXLAN, 100); + else + _LOGI ("Adding vxlan device via iproute2 failed. Assume iproute2 is not up to the task."); + } + if (!pllink) { + plerr = nm_platform_link_vxlan_add (NM_PLATFORM_GET, name, lnk, &pllink); + g_assert_cmpint (plerr, ==, NM_PLATFORM_ERROR_SUCCESS); + g_assert (pllink); + } + + g_assert_cmpint (pllink->type, ==, NM_LINK_TYPE_VXLAN); + g_assert_cmpstr (pllink->name, ==, name); + return pllink; +} + +void +nmtstp_ip4_address_add (gboolean external_command, + int ifindex, + in_addr_t address, + int plen, + in_addr_t peer_address, + guint32 lifetime, + guint32 preferred, + const char *label) +{ + _ip_address_add (external_command, + TRUE, + ifindex, + (NMIPAddr *) &address, + plen, + (NMIPAddr *) &peer_address, + lifetime, + preferred, + label, + 0); +} + +void +nmtstp_ip6_address_add (gboolean external_command, + int ifindex, + struct in6_addr address, + int plen, + struct in6_addr peer_address, + guint32 lifetime, + guint32 preferred, + guint flags) +{ + _ip_address_add (external_command, + FALSE, + ifindex, + (NMIPAddr *) &address, + plen, + (NMIPAddr *) &peer_address, + lifetime, + preferred, + NULL, + flags); +} + +static void +_ip_address_del (gboolean external_command, + gboolean is_v4, + int ifindex, + const NMIPAddr *address, + int plen, + const NMIPAddr *peer_address) +{ + gint64 end_time; + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + const char *ifname; + char b1[NM_UTILS_INET_ADDRSTRLEN], b2[NM_UTILS_INET_ADDRSTRLEN]; + int success; + gboolean had_address; + + ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); + g_assert (ifname); + + /* let's wait until we see the address as we added it. */ + if (is_v4) + had_address = !!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, address->addr4, plen, peer_address->addr4); + else + had_address = !!nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, address->addr6, plen); + + if (is_v4) { + success = nmtstp_run_command ("ip address delete %s%s%s/%d dev %s", + nm_utils_inet4_ntop (address->addr4, b1), + peer_address->addr4 != address->addr4 ? " peer " : "", + peer_address->addr4 != address->addr4 ? nm_utils_inet4_ntop (peer_address->addr4, b2) : "", + plen, + ifname); + } else { + g_assert (!peer_address); + success = nmtstp_run_command ("ip address delete %s/%d dev %s", + nm_utils_inet6_ntop (&address->addr6, b1), + plen, + ifname); + } + g_assert (success == 0 || !had_address); + } else { + gboolean success; + + if (is_v4) { + success = nm_platform_ip4_address_delete (NM_PLATFORM_GET, + ifindex, + address->addr4, + plen, + peer_address->addr4); + } else { + g_assert (!peer_address); + success = nm_platform_ip6_address_delete (NM_PLATFORM_GET, + ifindex, + address->addr6, + plen); + } + g_assert (success); + } + + /* Let's wait until we get the result */ + end_time = nm_utils_get_monotonic_timestamp_ms () + 250; + do { + if (external_command) + nm_platform_process_events (NM_PLATFORM_GET); + + /* let's wait until we see the address as we added it. */ + if (is_v4) { + const NMPlatformIP4Address *a; + + a = nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, address->addr4, plen, peer_address->addr4); + if (!a) + break; + } else { + const NMPlatformIP6Address *a; + + a = nm_platform_ip6_address_get (NM_PLATFORM_GET, ifindex, address->addr6, plen); + if (!a) + break; + } + + /* for internal command, we expect not to reach this line.*/ + g_assert (external_command); + + g_assert (nmtstp_wait_for_signal_until (end_time)); + } while (TRUE); +} + +void +nmtstp_ip4_address_del (gboolean external_command, + int ifindex, + in_addr_t address, + int plen, + in_addr_t peer_address) +{ + _ip_address_del (external_command, + TRUE, + ifindex, + (NMIPAddr *) &address, + plen, + (NMIPAddr *) &peer_address); +} + +void +nmtstp_ip6_address_del (gboolean external_command, + int ifindex, + struct in6_addr address, + int plen) +{ + _ip_address_del (external_command, + FALSE, + ifindex, + (NMIPAddr *) &address, + plen, + NULL); +} + +const NMPlatformLink * +nmtstp_link_get_typed (int ifindex, + const char *name, + NMLinkType link_type) +{ + const NMPlatformLink *pllink = NULL; + + if (ifindex > 0) { + pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex); + + if (pllink) { + g_assert_cmpint (pllink->ifindex, ==, ifindex); + if (name) + g_assert_cmpstr (name, ==, pllink->name); + } else { + if (name) + g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, name)); + } + } else { + g_assert (name); + + pllink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, name); + + if (pllink) + g_assert_cmpstr (name, ==, pllink->name); + } + + g_assert (!name || nm_utils_iface_valid_name (name)); + + if (pllink && link_type != NM_LINK_TYPE_NONE) + g_assert_cmpint (pllink->type, ==, link_type); + + return pllink; +} + +const NMPlatformLink * +nmtstp_link_get (int ifindex, + const char *name) +{ + return nmtstp_link_get_typed (ifindex, name, NM_LINK_TYPE_NONE); +} + +void +nmtstp_link_del (gboolean external_command, + int ifindex, + const char *name) +{ + gint64 end_time; + const NMPlatformLink *pllink; + gboolean success; + gs_free char *name_copy = NULL; + + pllink = nmtstp_link_get (ifindex, name); + + g_assert (pllink); + + name = name_copy = g_strdup (pllink->name); + ifindex = pllink->ifindex; + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + nmtstp_run_command_check ("ip link delete %s", name); + } else { + success = nm_platform_link_delete (NM_PLATFORM_GET, ifindex); + g_assert (success); + } + + /* Let's wait until we get the result */ + end_time = nm_utils_get_monotonic_timestamp_ms () + 250; + do { + if (external_command) + nm_platform_process_events (NM_PLATFORM_GET); + + if (!nm_platform_link_get (NM_PLATFORM_GET, ifindex)) { + g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, name)); + break; + } + + /* for internal command, we expect not to reach this line.*/ + g_assert (external_command); + + g_assert (nmtstp_wait_for_signal_until (end_time)); + } while (TRUE); } +void +nmtstp_link_set_updown (gboolean external_command, + int ifindex, + gboolean up) +{ + const NMPlatformLink *plink; + gint64 end_time; + + external_command = nmtstp_run_command_check_external (external_command); + + if (external_command) { + const char *ifname; + + ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); + g_assert (ifname); + + nmtstp_run_command_check ("ip link set %s %s", + ifname, + up ? "up" : "down"); + } else { + if (up) + g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL)); + else + g_assert (nm_platform_link_set_down (NM_PLATFORM_GET, ifindex)); + } + + /* Let's wait until we get the result */ + end_time = nm_utils_get_monotonic_timestamp_ms () + 250; + do { + if (external_command) + nm_platform_process_events (NM_PLATFORM_GET); + + /* let's wait until we see the address as we added it. */ + plink = nm_platform_link_get (NM_PLATFORM_GET, ifindex); + g_assert (plink); + + if (NM_FLAGS_HAS (plink->flags, IFF_UP) == !!up) + break; + + /* for internal command, we expect not to reach this line.*/ + g_assert (external_command); + + g_assert (nmtstp_wait_for_signal_until (end_time)); + } while (TRUE); +} + +/*****************************************************************************/ + +struct _NMTstpNamespaceHandle { + pid_t pid; + int pipe_fd; +}; + +NMTstpNamespaceHandle * +nmtstp_namespace_create (int unshare_flags, GError **error) +{ + NMTstpNamespaceHandle *ns_handle; + int e; + int errsv; + pid_t pid, pid2; + int pipefd_c2p[2]; + int pipefd_p2c[2]; + ssize_t r; + + e = pipe (pipefd_c2p); + if (e != 0) { + errsv = errno; + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "pipe() failed with %d (%s)", errsv, strerror (errsv)); + return FALSE; + } + + e = pipe (pipefd_p2c); + if (e != 0) { + errsv = errno; + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "pipe() failed with %d (%s)", errsv, strerror (errsv)); + close (pipefd_c2p[0]); + close (pipefd_c2p[1]); + return FALSE; + } + + pid = fork (); + if (pid < 0) { + errsv = errno; + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "fork() failed with %d (%s)", errsv, strerror (errsv)); + close (pipefd_c2p[0]); + close (pipefd_c2p[1]); + close (pipefd_p2c[0]); + close (pipefd_p2c[1]); + return FALSE; + } + + if (pid == 0) { + char read_buf[1]; + + close (pipefd_c2p[0]); /* close read-end */ + close (pipefd_p2c[1]); /* close write-end */ + + if (unshare (unshare_flags) != 0) { + errsv = errno; + if (errsv == 0) + errsv = -1; + } else + errsv = 0; + + /* sync with parent process and send result. */ + do { + r = write (pipefd_c2p[1], &errsv, sizeof (errsv)); + } while (r < 0 && errno == EINTR); + if (r != sizeof (errsv)) { + errsv = errno; + if (errsv == 0) + errsv = -2; + } + close (pipefd_c2p[1]); + + /* wait until parent process terminates (or kills us). */ + if (errsv == 0) { + do { + r = read (pipefd_p2c[0], read_buf, sizeof (read_buf)); + } while (r < 0 && errno == EINTR); + } + close (pipefd_p2c[0]); + _exit (0); + } + + close (pipefd_c2p[1]); /* close write-end */ + close (pipefd_p2c[0]); /* close read-end */ + + /* sync with child process. */ + do { + r = read (pipefd_c2p[0], &errsv, sizeof (errsv)); + } while (r < 0 && errno == EINTR); + + close (pipefd_c2p[0]); + + if ( r != sizeof (errsv) + || errsv != 0) { + int status; + + if (r != sizeof (errsv)) { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "child process failed for unknown reason"); + } else { + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "child process signaled failure %d (%s)", errsv, strerror (errsv)); + } + close (pipefd_p2c[1]); + kill (pid, SIGKILL); + do { + pid2 = waitpid (pid, &status, 0); + } while (pid2 == -1 && errno == EINTR); + return FALSE; + } + + ns_handle = g_new0 (NMTstpNamespaceHandle, 1); + ns_handle->pid = pid; + ns_handle->pipe_fd = pipefd_p2c[1]; + return ns_handle; +} + +pid_t +nmtstp_namespace_handle_get_pid (NMTstpNamespaceHandle *ns_handle) +{ + g_return_val_if_fail (ns_handle, 0); + g_return_val_if_fail (ns_handle->pid > 0, 0); + + return ns_handle->pid; +} + +void +nmtstp_namespace_handle_release (NMTstpNamespaceHandle *ns_handle) +{ + pid_t pid; + int status; + + if (!ns_handle) + return; + + g_return_if_fail (ns_handle->pid > 0); + + close (ns_handle->pipe_fd); + ns_handle->pipe_fd = 0; + + kill (ns_handle->pid, SIGKILL); + + do { + pid = waitpid (ns_handle->pid, &status, 0); + } while (pid == -1 && errno == EINTR); + ns_handle->pid = 0; + + g_free (ns_handle); +} + +int +nmtstp_namespace_get_fd_for_process (pid_t pid, const char *ns_name) +{ + char p[1000]; + + g_return_val_if_fail (pid > 0, 0); + g_return_val_if_fail (ns_name && ns_name[0] && strlen (ns_name) < 50, 0); + + nm_sprintf_buf (p, "/proc/%lu/ns/%s", (long unsigned) pid, ns_name); + + return open(p, O_RDONLY); +} + +/*****************************************************************************/ + NMTST_DEFINE(); static gboolean @@ -318,7 +1487,7 @@ main (int argc, char **argv) init_tests (&argc, &argv); - if ( nmtst_platform_is_root_test () + if ( nmtstp_is_root_test () && (geteuid () != 0 || getegid () != 0)) { if ( g_getenv ("NMTST_FORCE_REAL_ROOT") || !unshare_user ()) { @@ -335,7 +1504,7 @@ main (int argc, char **argv) } } - if (nmtst_platform_is_root_test () && !g_getenv ("NMTST_NO_UNSHARE")) { + if (nmtstp_is_root_test () && !g_getenv ("NMTST_NO_UNSHARE")) { int errsv; if (unshare (CLONE_NEWNET | CLONE_NEWNS) != 0) { @@ -345,10 +1514,7 @@ main (int argc, char **argv) /* Mount our /sys instance, so that gudev sees only our devices. * Needs to be read-only, because we don't run udev. */ - if (mount (NULL, "/sys", "sysfs", MS_SLAVE, NULL) != 0) { - errsv = errno; - g_error ("mount(\"/\", MS_SLAVE) failed with %s (%d)", strerror (errsv), errsv); - } + mount (NULL, "/sys", "sysfs", MS_SLAVE, NULL); if (mount ("sys", "/sys", "sysfs", MS_RDONLY, NULL) != 0) { errsv = errno; g_error ("mount(\"/sys\") failed with %s (%d)", strerror (errsv), errsv); @@ -383,6 +1549,6 @@ main (int argc, char **argv) nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)); - g_object_unref (nm_platform_get ()); + g_object_unref (NM_PLATFORM_GET); return result; } diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index 3d647543..0281d3c5 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -4,7 +4,7 @@ #include #include -#include "nm-logging.h" +#include "nm-default.h" #include "nm-platform.h" #include "nm-fake-platform.h" #include "nm-linux-platform.h" @@ -13,10 +13,33 @@ #define DEVICE_NAME "nm-test-device" -#define debug(...) nm_log_dbg (LOGD_PLATFORM, __VA_ARGS__) +/*********************************************************************************************/ + +#define _NMLOG_PREFIX_NAME "platform-test" +#define _NMLOG_DOMAIN LOGD_PLATFORM +#define _NMLOG(level, ...) _LOG(level, _NMLOG_DOMAIN, __VA_ARGS__) + +#define _LOG(level, domain, ...) \ + G_STMT_START { \ + const NMLogLevel __level = (level); \ + const NMLogDomain __domain = (domain); \ + \ + if (nm_logging_enabled (__level, __domain)) { \ + gint64 _ts = nm_utils_get_monotonic_timestamp_ns (); \ + \ + _nm_log (__level, __domain, 0, \ + "%s[%ld.%09ld]: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + (long) (_ts / NM_UTILS_NS_PER_SECOND), \ + (long) (_ts % NM_UTILS_NS_PER_SECOND) \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } \ + } G_STMT_END + +/*********************************************************************************************/ typedef struct { - int handler_id; + gulong handler_id; const char *name; NMPlatformSignalChangeType change_type; gint received_count; @@ -25,8 +48,21 @@ typedef struct { const char *ifname; } SignalData; -gboolean nmtst_platform_is_root_test (void); -gboolean nmtst_platform_is_sysfs_writable (void); +gboolean nmtstp_is_root_test (void); +gboolean nmtstp_is_sysfs_writable (void); + +/******************************************************************************/ + +typedef struct _NMTstpNamespaceHandle NMTstpNamespaceHandle; + +NMTstpNamespaceHandle *nmtstp_namespace_create (int flags, GError **error); + +void nmtstp_namespace_handle_release (NMTstpNamespaceHandle *handle); +pid_t nmtstp_namespace_handle_get_pid (NMTstpNamespaceHandle *handle); + +int nmtstp_namespace_get_fd_for_process (pid_t pid, const char *ns_name); + +/******************************************************************************/ 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) @@ -35,11 +71,13 @@ SignalData *add_signal_full (const char *name, NMPlatformSignalChangeType change void _accept_signal (const char *file, int line, const char *func, SignalData *data); void _accept_signals (const char *file, int line, const char *func, SignalData *data, int min, int max); void _wait_signal (const char *file, int line, const char *func, SignalData *data); +void _accept_or_wait_signal (const char *file, int line, const char *func, SignalData *data); void _ensure_no_signal (const char *file, int line, const char *func, SignalData *data); void _free_signal (const char *file, int line, const char *func, SignalData *data); #define accept_signal(data) _accept_signal(__FILE__, __LINE__, G_STRFUNC, data) #define accept_signals(data, min, max) _accept_signals(__FILE__, __LINE__, G_STRFUNC, data, min, max) #define wait_signal(data) _wait_signal(__FILE__, __LINE__, G_STRFUNC, data) +#define accept_or_wait_signal(data) _accept_or_wait_signal(__FILE__, __LINE__, G_STRFUNC, data) #define ensure_no_signal(data) _ensure_no_signal(__FILE__, __LINE__, G_STRFUNC, data) #define free_signal(data) _free_signal(__FILE__, __LINE__, G_STRFUNC, data) @@ -48,9 +86,88 @@ gboolean ip4_route_exists (const char *ifname, guint32 network, int plen, guint3 void _assert_ip4_route_exists (const char *file, guint line, const char *func, gboolean exists, const char *ifname, guint32 network, int plen, guint32 metric); #define assert_ip4_route_exists(exists, ifname, network, plen, metric) _assert_ip4_route_exists (__FILE__, __LINE__, G_STRFUNC, exists, ifname, network, plen, metric) -void link_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformLink *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data); +void link_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, NMPlatformLink *received, NMPlatformSignalChangeType change_type, SignalData *data); + +int nmtstp_run_command (const char *format, ...) __attribute__((__format__ (__printf__, 1, 2))); +#define nmtstp_run_command_check(...) do { g_assert_cmpint (nmtstp_run_command (__VA_ARGS__), ==, 0); } while (0) + +gboolean nmtstp_wait_for_signal (guint timeout_ms); +gboolean nmtstp_wait_for_signal_until (gint64 until_ms); +const NMPlatformLink *nmtstp_wait_for_link (const char *ifname, NMLinkType expected_link_type, guint timeout_ms); +const NMPlatformLink *nmtstp_wait_for_link_until (const char *ifname, NMLinkType expected_link_type, gint64 until_ms); + +const NMPlatformLink *nmtstp_assert_wait_for_link (const char *ifname, NMLinkType expected_link_type, guint timeout_ms); +const NMPlatformLink *nmtstp_assert_wait_for_link_until (const char *ifname, NMLinkType expected_link_type, gint64 until_ms); + +int nmtstp_run_command_check_external_global (void); +gboolean nmtstp_run_command_check_external (int external_command); + +gboolean nmtstp_ip_address_check_lifetime (const NMPlatformIPAddress *addr, + gint64 now, + guint32 expected_lifetime, + guint32 expected_preferred); +void nmtstp_ip_address_assert_lifetime (const NMPlatformIPAddress *addr, + gint64 now, + guint32 expected_lifetime, + guint32 expected_preferred); +void nmtstp_ip4_address_add (gboolean external_command, + int ifindex, + in_addr_t address, + int plen, + in_addr_t peer_address, + guint32 lifetime, + guint32 preferred, + const char *label); +void nmtstp_ip6_address_add (gboolean external_command, + int ifindex, + struct in6_addr address, + int plen, + struct in6_addr peer_address, + guint32 lifetime, + guint32 preferred, + guint flags); +void nmtstp_ip4_address_del (gboolean external_command, + int ifindex, + in_addr_t address, + int plen, + in_addr_t peer_address); +void nmtstp_ip6_address_del (gboolean external_command, + int ifindex, + struct in6_addr address, + int plen); + +const NMPlatformLink *nmtstp_link_get_typed (int ifindex, const char *name, NMLinkType link_type); +const NMPlatformLink *nmtstp_link_get (int ifindex, const char *name); + +void nmtstp_link_set_updown (gboolean external_command, + int ifindex, + gboolean up); + +const NMPlatformLink *nmtstp_link_dummy_add (gboolean external_command, + const char *name); +const NMPlatformLink *nmtstp_link_gre_add (gboolean external_command, + const char *name, + const NMPlatformLnkGre *lnk); +const NMPlatformLink *nmtstp_link_ip6tnl_add (gboolean external_command, + const char *name, + const NMPlatformLnkIp6Tnl *lnk); +const NMPlatformLink *nmtstp_link_ipip_add (gboolean external_command, + const char *name, + const NMPlatformLnkIpIp *lnk); +const NMPlatformLink *nmtstp_link_macvlan_add (gboolean external_command, + const char *name, + int parent, + const NMPlatformLnkMacvlan *lnk); +const NMPlatformLink *nmtstp_link_sit_add (gboolean external_command, + const char *name, + const NMPlatformLnkSit *lnk); +const NMPlatformLink *nmtstp_link_vxlan_add (gboolean external_command, + const char *name, + const NMPlatformLnkVxlan *lnk); -void run_command (const char *format, ...); +void nmtstp_link_del (gboolean external_command, + int ifindex, + const char *name); void init_tests (int *argc, char ***argv); void setup_tests (void); diff --git a/src/platform/tests/test-general.c b/src/platform/tests/test-general.c index 0a397b37..f342e565 100644 --- a/src/platform/tests/test-general.c +++ b/src/platform/tests/test-general.c @@ -23,7 +23,7 @@ #include #include "nm-linux-platform.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-test-utils.h" @@ -65,3 +65,4 @@ main (int argc, char **argv) return g_test_run (); } + diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index 47cbcec1..8b496262 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -1,5 +1,9 @@ #include "config.h" +#include + +#include "nmp-object.h" + #include "test-common.h" #include "nm-test-utils.h" @@ -28,10 +32,18 @@ test_bogus(void) g_assert (!nm_platform_link_get_type (NM_PLATFORM_GET, BOGUS_IFINDEX)); g_assert (!nm_platform_link_get_type_name (NM_PLATFORM_GET, BOGUS_IFINDEX)); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*failure changing link: *"); g_assert (!nm_platform_link_set_up (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL)); + + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*failure changing link: *"); g_assert (!nm_platform_link_set_down (NM_PLATFORM_GET, BOGUS_IFINDEX)); + + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*failure changing link: *"); g_assert (!nm_platform_link_set_arp (NM_PLATFORM_GET, BOGUS_IFINDEX)); + + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*failure changing link: *"); g_assert (!nm_platform_link_set_noarp (NM_PLATFORM_GET, BOGUS_IFINDEX)); + g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, BOGUS_IFINDEX)); g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, BOGUS_IFINDEX)); g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, BOGUS_IFINDEX)); @@ -39,15 +51,18 @@ test_bogus(void) g_assert (!nm_platform_link_get_address (NM_PLATFORM_GET, BOGUS_IFINDEX, &addrlen)); g_assert (!addrlen); g_assert (!nm_platform_link_get_address (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL)); + + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, "*failure changing link: *"); g_assert (!nm_platform_link_set_mtu (NM_PLATFORM_GET, BOGUS_IFINDEX, MTU)); + g_assert (!nm_platform_link_get_mtu (NM_PLATFORM_GET, BOGUS_IFINDEX)); g_assert (!nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, BOGUS_IFINDEX)); g_assert (!nm_platform_link_supports_vlans (NM_PLATFORM_GET, BOGUS_IFINDEX)); - g_assert (!nm_platform_vlan_get_info (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL, NULL)); - g_assert (!nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, BOGUS_IFINDEX, 0, 0)); - g_assert (!nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, BOGUS_IFINDEX, 0, 0)); + g_assert (!nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL)); + g_assert (!nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, BOGUS_IFINDEX, 0, 0)); + g_assert (!nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, BOGUS_IFINDEX, 0, 0)); } static void @@ -68,15 +83,15 @@ software_add (NMLinkType link_type, const char *name) { switch (link_type) { case NM_LINK_TYPE_DUMMY: - return nm_platform_dummy_add (NM_PLATFORM_GET, name, NULL) == NM_PLATFORM_ERROR_SUCCESS; + return nm_platform_link_dummy_add (NM_PLATFORM_GET, name, NULL) == NM_PLATFORM_ERROR_SUCCESS; case NM_LINK_TYPE_BRIDGE: - return nm_platform_bridge_add (NM_PLATFORM_GET, name, NULL, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS; + return nm_platform_link_bridge_add (NM_PLATFORM_GET, name, NULL, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS; case NM_LINK_TYPE_BOND: { gboolean bond0_exists = !!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "bond0"); NMPlatformError plerr; - plerr = nm_platform_bond_add (NM_PLATFORM_GET, name, NULL); + plerr = nm_platform_link_bond_add (NM_PLATFORM_GET, name, NULL); /* Check that bond0 is *not* automatically created. */ if (!bond0_exists) @@ -84,14 +99,14 @@ software_add (NMLinkType link_type, const char *name) return plerr == NM_PLATFORM_ERROR_SUCCESS; } case NM_LINK_TYPE_TEAM: - return nm_platform_team_add (NM_PLATFORM_GET, name, NULL) == NM_PLATFORM_ERROR_SUCCESS; + return nm_platform_link_team_add (NM_PLATFORM_GET, name, NULL) == NM_PLATFORM_ERROR_SUCCESS; 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 (NM_PLATFORM_GET, PARENT_NAME, NULL, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS) + if (nm_platform_link_bridge_add (NM_PLATFORM_GET, PARENT_NAME, NULL, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS) accept_signal (parent_added); free_signal (parent_added); @@ -108,7 +123,7 @@ software_add (NMLinkType link_type, const char *name) accept_signal (parent_changed); free_signal (parent_changed); - return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent_ifindex, VLAN_ID, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS; + return nm_platform_link_vlan_add (NM_PLATFORM_GET, name, parent_ifindex, VLAN_ID, 0, NULL) == NM_PLATFORM_ERROR_SUCCESS; } } default: @@ -123,7 +138,6 @@ test_link_changed_signal_cb (NMPlatform *platform, int ifindex, const NMPlatformIP4Route *route, NMPlatformSignalChangeType change_type, - NMPlatformReason reason, gboolean *p_test_link_changed_signal_arg) { /* test invocation of platform signals with multiple listeners @@ -146,9 +160,6 @@ test_link_changed_signal_cb (NMPlatform *platform, g_assert_cmpint ((gint64) change_type, !=, (gint64) 0); g_assert_cmpint (change_type, !=, NM_PLATFORM_SIGNAL_NONE); - g_assert_cmpint ((gint64) reason, !=, (gint64) 0); - g_assert_cmpint (reason, !=, NM_PLATFORM_REASON_NONE); - *p_test_link_changed_signal_arg = TRUE; } @@ -262,9 +273,9 @@ test_slave (int master, int type, SignalData *master_changed) /* Set slave option */ switch (type) { case NM_LINK_TYPE_BRIDGE: - if (nmtst_platform_is_sysfs_writable ()) { - g_assert (nm_platform_slave_set_option (NM_PLATFORM_GET, ifindex, "priority", "789")); - value = nm_platform_slave_get_option (NM_PLATFORM_GET, ifindex, "priority"); + if (nmtstp_is_sysfs_writable ()) { + g_assert (nm_platform_sysctl_slave_set_option (NM_PLATFORM_GET, ifindex, "priority", "789")); + value = nm_platform_sysctl_slave_get_option (NM_PLATFORM_GET, ifindex, "priority"); g_assert_cmpstr (value, ==, "789"); g_free (value); } @@ -296,7 +307,7 @@ test_slave (int master, int type, SignalData *master_changed) ensure_no_signal (link_added); ensure_no_signal (link_changed); ensure_no_signal (link_removed); - g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex)); + nmtstp_link_del (-1, ifindex, NULL); accept_signals (master_changed, 0, 1); accept_signals (link_changed, 0, 1); accept_signal (link_removed); @@ -311,7 +322,7 @@ test_software (NMLinkType link_type, const char *link_typename) { int ifindex; char *value; - int vlan_parent, vlan_id; + int vlan_parent = -1, vlan_id; SignalData *link_added, *link_changed, *link_removed; @@ -327,7 +338,15 @@ test_software (NMLinkType link_type, const char *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 (NM_PLATFORM_GET, ifindex, &vlan_parent, &vlan_id)); + const NMPlatformLink *plink; + const NMPlatformLnkVlan *plnk; + + plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, &plink); + g_assert (plnk); + g_assert (plink); + + vlan_parent = plink->parent; + vlan_id = plnk->id; g_assert_cmpint (vlan_parent, ==, nm_platform_link_get_ifindex (NM_PLATFORM_GET, PARENT_NAME)); g_assert_cmpint (vlan_id, ==, VLAN_ID); } @@ -347,17 +366,17 @@ test_software (NMLinkType link_type, const char *link_typename) /* Set master option */ switch (link_type) { case NM_LINK_TYPE_BRIDGE: - if (nmtst_platform_is_sysfs_writable ()) { - g_assert (nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, "forward_delay", "789")); - value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, "forward_delay"); + if (nmtstp_is_sysfs_writable ()) { + g_assert (nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, "forward_delay", "789")); + value = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, "forward_delay"); g_assert_cmpstr (value, ==, "789"); g_free (value); } break; case NM_LINK_TYPE_BOND: - if (nmtst_platform_is_sysfs_writable ()) { - g_assert (nm_platform_master_set_option (NM_PLATFORM_GET, ifindex, "mode", "active-backup")); - value = nm_platform_master_get_option (NM_PLATFORM_GET, ifindex, "mode"); + if (nmtstp_is_sysfs_writable ()) { + g_assert (nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, "mode", "active-backup")); + value = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, "mode"); /* When reading back, the output looks slightly different. */ g_assert (g_str_has_prefix (value, "active-backup")); g_free (value); @@ -382,20 +401,18 @@ test_software (NMLinkType link_type, const char *link_typename) free_signal (link_changed); /* Delete */ - g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex)); - g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME)); - g_assert_cmpint (nm_platform_link_get_type (NM_PLATFORM_GET, ifindex), ==, NM_LINK_TYPE_NONE); - g_assert (!nm_platform_link_get_type (NM_PLATFORM_GET, ifindex)); + nmtstp_link_del (-1, ifindex, DEVICE_NAME); accept_signal (link_removed); /* Delete again */ g_assert (!nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME))); + g_assert (!nm_platform_link_delete (NM_PLATFORM_GET, ifindex)); /* 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 (NM_PLATFORM_GET, vlan_parent)); + nmtstp_link_del (-1, vlan_parent, NULL); accept_signal (link_removed_parent); free_signal (link_removed_parent); } @@ -414,7 +431,7 @@ test_bridge (void) static void test_bond (void) { - if (nmtst_platform_is_root_test () && + if (nmtstp_is_root_test () && !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"); @@ -436,6 +453,53 @@ test_vlan (void) test_software (NM_LINK_TYPE_VLAN, "vlan"); } +/*****************************************************************************/ + +static void +test_bridge_addr (void) +{ + char addr[ETH_ALEN]; + NMPlatformLink link; + const NMPlatformLink *plink = NULL; + + nm_utils_hwaddr_aton ("de:ad:be:ef:00:11", addr, sizeof (addr)); + + g_assert_cmpint (nm_platform_link_bridge_add (NM_PLATFORM_GET, DEVICE_NAME, addr, sizeof (addr), &plink), ==, NM_PLATFORM_ERROR_SUCCESS); + g_assert (plink); + link = *plink; + g_assert_cmpstr (link.name, ==, DEVICE_NAME); + + g_assert_cmpint (link.addr.len, ==, sizeof (addr)); + g_assert (!memcmp (link.addr.data, addr, sizeof (addr))); + + plink = nm_platform_link_get (NM_PLATFORM_GET, link.ifindex); + g_assert (plink); + + if (nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET)) { + g_assert (!nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex)); + g_assert_cmpint (_nm_platform_uint8_inv (plink->inet6_addr_gen_mode_inv), ==, NM_IN6_ADDR_GEN_MODE_EUI64); + + g_assert (nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex, TRUE)); + g_assert (nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex)); + plink = nm_platform_link_get (NM_PLATFORM_GET, link.ifindex); + g_assert (plink); + g_assert_cmpint (_nm_platform_uint8_inv (plink->inet6_addr_gen_mode_inv), ==, NM_IN6_ADDR_GEN_MODE_NONE); + + g_assert (nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex, FALSE)); + g_assert (!nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex)); + plink = nm_platform_link_get (NM_PLATFORM_GET, link.ifindex); + g_assert (plink); + g_assert_cmpint (_nm_platform_uint8_inv (plink->inet6_addr_gen_mode_inv), ==, NM_IN6_ADDR_GEN_MODE_EUI64); + } + + g_assert_cmpint (plink->addr.len, ==, sizeof (addr)); + g_assert (!memcmp (plink->addr.data, addr, sizeof (addr))); + + nmtstp_link_del (-1, link.ifindex, link.name); +} + +/*****************************************************************************/ + static void test_internal (void) { @@ -451,11 +515,11 @@ test_internal (void) g_assert (!nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)); /* Add device */ - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS); + g_assert (nm_platform_link_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS); accept_signal (link_added); /* Try to add again */ - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_EXISTS); + g_assert (nm_platform_link_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_EXISTS); /* Check device index, name and type */ ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); @@ -506,7 +570,7 @@ test_internal (void) accept_signal (link_changed); /* Delete device */ - g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex)); + nmtstp_link_del (-1, ifindex, DEVICE_NAME); accept_signal (link_removed); /* Try to delete again */ @@ -517,15 +581,18 @@ test_internal (void) free_signal (link_removed); } +/*****************************************************************************/ + static void test_external (void) { const NMPlatformLink *pllink; - SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME); - SignalData *link_changed, *link_removed; + SignalData *link_added, *link_changed, *link_removed; int ifindex; - run_command ("ip link add %s type %s", DEVICE_NAME, "dummy"); + link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME); + + nmtstp_run_command_check ("ip link add %s type %s", DEVICE_NAME, "dummy"); wait_signal (link_added); g_assert (nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME)); @@ -549,24 +616,24 @@ test_external (void) g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex)); g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex)); - run_command ("ip link set %s up", DEVICE_NAME); + nmtstp_run_command_check ("ip link set %s up", DEVICE_NAME); wait_signal (link_changed); g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, ifindex)); g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex)); - run_command ("ip link set %s down", DEVICE_NAME); + nmtstp_run_command_check ("ip link set %s down", DEVICE_NAME); wait_signal (link_changed); g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex)); g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex)); - run_command ("ip link set %s arp on", DEVICE_NAME); + nmtstp_run_command_check ("ip link set %s arp on", DEVICE_NAME); wait_signal (link_changed); g_assert (nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex)); - run_command ("ip link set %s arp off", DEVICE_NAME); + nmtstp_run_command_check ("ip link set %s arp off", DEVICE_NAME); wait_signal (link_changed); g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex)); - run_command ("ip link del %s", DEVICE_NAME); + nmtstp_run_command_check ("ip link del %s", DEVICE_NAME); wait_signal (link_removed); accept_signals (link_changed, 0, 1); g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME)); @@ -576,6 +643,1183 @@ test_external (void) free_signal (link_removed); } +/*****************************************************************************/ + +typedef struct { + NMLinkType link_type; + int test_mode; + gboolean external_command; +} TestAddSoftwareDetectData; + +static void +test_software_detect (gconstpointer user_data) +{ + const TestAddSoftwareDetectData *test_data = user_data; + int ifindex, ifindex_parent; + const NMPlatformLink *plink; + const NMPObject *lnk; + guint i_step; + const gboolean ext = test_data->external_command; + + nmtstp_run_command_check ("ip link add %s type dummy", PARENT_NAME); + ifindex_parent = nmtstp_assert_wait_for_link (PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex; + + switch (test_data->link_type) { + case NM_LINK_TYPE_GRE: { + NMPlatformLnkGre lnk_gre = { }; + gboolean gracefully_skip = FALSE; + + lnk_gre.local = nmtst_inet4_from_string ("192.168.233.204"); + lnk_gre.remote = nmtst_inet4_from_string ("172.168.10.25"); + lnk_gre.parent_ifindex = ifindex_parent; + lnk_gre.ttl = 174; + lnk_gre.tos = 37; + lnk_gre.path_mtu_discovery = TRUE; + + if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "gre0")) { + /* Seems that the ip_gre module is not loaded... try to load it. */ + gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip_gre", NULL) != 0; + } + + if (!nmtstp_link_gre_add (ext, DEVICE_NAME, &lnk_gre)) { + if (gracefully_skip) { + g_test_skip ("Cannot create gre tunnel because of missing ip_gre module (modprobe ip_gre)"); + goto out_delete_parent; + } + g_error ("Failed adding GRE tunnel"); + } + break; + } + case NM_LINK_TYPE_IPIP: { + NMPlatformLnkIpIp lnk_ipip = { }; + gboolean gracefully_skip = FALSE; + + if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "tunl0")) { + /* Seems that the ipip module is not loaded... try to load it. */ + gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ipip", NULL) != 0; + } + + lnk_ipip.local = nmtst_inet4_from_string ("1.2.3.4"); + lnk_ipip.remote = nmtst_inet4_from_string ("5.6.7.8"); + lnk_ipip.parent_ifindex = ifindex_parent; + lnk_ipip.tos = 32; + lnk_ipip.path_mtu_discovery = FALSE; + + if (!nmtstp_link_ipip_add (ext, DEVICE_NAME, &lnk_ipip)) { + if (gracefully_skip) { + g_test_skip ("Cannot create ipip tunnel because of missing ipip module (modprobe ipip)"); + goto out_delete_parent; + } + g_error ("Failed adding IPIP tunnel"); + } + break; + } + case NM_LINK_TYPE_IP6TNL: { + NMPlatformLnkIp6Tnl lnk_ip6tnl = { }; + gboolean gracefully_skip = FALSE; + + if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "ip6tnl0")) { + /* Seems that the ip6_tunnel module is not loaded... try to load it. */ + gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip6_tunnel", NULL) != 0; + } + + lnk_ip6tnl.local = *nmtst_inet6_from_string ("fd01::15"); + lnk_ip6tnl.remote = *nmtst_inet6_from_string ("fd01::16"); + lnk_ip6tnl.parent_ifindex = ifindex_parent; + lnk_ip6tnl.tclass = 20; + lnk_ip6tnl.encap_limit = 6; + lnk_ip6tnl.flow_label = 1337; + lnk_ip6tnl.proto = IPPROTO_IPV6; + + if (!nmtstp_link_ip6tnl_add (ext, DEVICE_NAME, &lnk_ip6tnl)) { + if (gracefully_skip) { + g_test_skip ("Cannot create ip6tnl tunnel because of missing ip6_tunnel module (modprobe ip6_tunnel)"); + goto out_delete_parent; + } + g_error ("Failed adding IP6TNL tunnel"); + } + break; + } + case NM_LINK_TYPE_MACVLAN: { + NMPlatformLnkMacvlan lnk_macvlan = { }; + + lnk_macvlan.mode = MACVLAN_MODE_BRIDGE; + lnk_macvlan.no_promisc = FALSE; + lnk_macvlan.tap = FALSE; + + if (!nmtstp_link_macvlan_add (ext, DEVICE_NAME, ifindex_parent, &lnk_macvlan)) + g_error ("Failed adding MACVLAN interface"); + break; + } + case NM_LINK_TYPE_MACVTAP: { + NMPlatformLnkMacvtap lnk_macvtap = { }; + + lnk_macvtap.mode = MACVLAN_MODE_PRIVATE; + lnk_macvtap.no_promisc = FALSE; + lnk_macvtap.tap = TRUE; + + if (!nmtstp_link_macvlan_add (ext, DEVICE_NAME, ifindex_parent, &lnk_macvtap)) + g_error ("Failed adding MACVTAP interface"); + break; + } + case NM_LINK_TYPE_SIT: { + NMPlatformLnkSit lnk_sit = { }; + gboolean gracefully_skip = FALSE; + + lnk_sit.local = nmtst_inet4_from_string ("192.168.200.1"); + lnk_sit.remote = nmtst_inet4_from_string ("172.25.100.14"); + lnk_sit.parent_ifindex = ifindex_parent; + lnk_sit.ttl = 0; + lnk_sit.tos = 31; + lnk_sit.path_mtu_discovery = FALSE; + + if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "sit0")) { + /* Seems that the sit module is not loaded... try to load it. */ + gracefully_skip = nm_utils_modprobe (NULL, TRUE, "sit", NULL) != 0; + } + + if (!nmtstp_link_sit_add (ext, DEVICE_NAME, &lnk_sit)) { + if (gracefully_skip) { + g_test_skip ("Cannot create sit tunnel because of missing sit module (modprobe sit)"); + goto out_delete_parent; + } + g_error ("Failed adding SIT tunnel"); + } + break; + } + case NM_LINK_TYPE_VLAN: + nmtstp_run_command_check ("ip link add name %s link %s type vlan id 1242", DEVICE_NAME, PARENT_NAME); + break; + case NM_LINK_TYPE_VXLAN: { + NMPlatformLnkVxlan lnk_vxlan = { }; + + switch (test_data->test_mode) { + case 0: + lnk_vxlan.parent_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, PARENT_NAME); + lnk_vxlan.id = 42; + lnk_vxlan.local = nmtst_inet4_from_string ("23.1.2.164"); + lnk_vxlan.group = nmtst_inet4_from_string ("239.1.2.134"); + lnk_vxlan.dst_port = 4789; + lnk_vxlan.learning = TRUE; + lnk_vxlan.ageing = 1245; + break; + case 1: + lnk_vxlan.parent_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, PARENT_NAME); + lnk_vxlan.id = 11214423; + lnk_vxlan.local6 = *nmtst_inet6_from_string ("1:2:3:4:334:23::23"); + lnk_vxlan.group6 = *nmtst_inet6_from_string ("ff0e::115"); + lnk_vxlan.ttl = 32; + lnk_vxlan.dst_port = 57412; + lnk_vxlan.src_port_min = 1000; + lnk_vxlan.src_port_max = 1003; + lnk_vxlan.learning = TRUE; + lnk_vxlan.ageing = 3245; + break; + } + + g_assert (nmtstp_link_vxlan_add (ext, DEVICE_NAME, &lnk_vxlan)); + break; + } + default: + g_assert_not_reached (); + } + + ifindex = nmtstp_assert_wait_for_link (DEVICE_NAME, test_data->link_type, 100)->ifindex; + + nmtstp_link_set_updown (-1, ifindex_parent, TRUE); + + for (i_step = 0; i_step < 5; i_step++) { + + _LOGD ("test-software-detect: step %u", i_step); + if (nmtst_is_debug ()) + nmtstp_run_command_check ("ip -d link show %s", DEVICE_NAME); + + if (i_step > 0) { + gboolean set_up = (i_step % 2) == 1; + + if ( test_data->link_type == NM_LINK_TYPE_VXLAN + && set_up) { + /* On RHEL-7, we need to add a tiny sleep here, otherwise, + * upping the vxlan device fails with EADDRINUSE. + * https://bugzilla.redhat.com/show_bug.cgi?id=1277131 */ + g_usleep (1); + } + nmtstp_link_set_updown (-1, ifindex, set_up); + } + + lnk = nm_platform_link_get_lnk (NM_PLATFORM_GET, ifindex, test_data->link_type, &plink); + g_assert (plink); + g_assert_cmpint (plink->ifindex, ==, ifindex); + g_assert (lnk); + + switch (test_data->link_type) { + case NM_LINK_TYPE_GRE: { + const NMPlatformLnkGre *plnk = &lnk->lnk_gre; + + g_assert (plnk == nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); + g_assert_cmpint (plnk->input_flags, ==, 0); + g_assert_cmpint (plnk->output_flags, ==, 0); + g_assert_cmpint (plnk->input_key, ==, 0); + g_assert_cmpint (plnk->output_key, ==, 0); + nmtst_assert_ip4_address (plnk->local, "192.168.233.204"); + nmtst_assert_ip4_address (plnk->remote, "172.168.10.25"); + g_assert_cmpint (plnk->ttl, ==, 174); + g_assert_cmpint (plnk->tos, ==, 37); + g_assert_cmpint (plnk->path_mtu_discovery, ==, TRUE); + break; + } + case NM_LINK_TYPE_IP6TNL: { + const NMPlatformLnkIp6Tnl *plnk = &lnk->lnk_ip6tnl; + + g_assert (plnk == nm_platform_link_get_lnk_ip6tnl (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); + nmtst_assert_ip6_address (&plnk->local, "fd01::15"); + nmtst_assert_ip6_address (&plnk->remote, "fd01::16"); + g_assert_cmpint (plnk->ttl, ==, 0); + g_assert_cmpint (plnk->tclass, ==, 20); + g_assert_cmpint (plnk->encap_limit, ==, 6); + g_assert_cmpint (plnk->flow_label, ==, 1337); + g_assert_cmpint (plnk->proto, ==, IPPROTO_IPV6); + break; + } + case NM_LINK_TYPE_IPIP: { + const NMPlatformLnkIpIp *plnk = &lnk->lnk_ipip; + + g_assert (plnk == nm_platform_link_get_lnk_ipip (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); + nmtst_assert_ip4_address (plnk->local, "1.2.3.4"); + nmtst_assert_ip4_address (plnk->remote, "5.6.7.8"); + g_assert_cmpint (plnk->ttl, ==, 0); + g_assert_cmpint (plnk->tos, ==, 32); + g_assert_cmpint (plnk->path_mtu_discovery, ==, FALSE); + break; + } + case NM_LINK_TYPE_MACVLAN: { + const NMPlatformLnkMacvlan *plnk = &lnk->lnk_macvlan; + + g_assert (plnk == nm_platform_link_get_lnk_macvlan (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->no_promisc, ==, FALSE); + g_assert_cmpint (plnk->mode, ==, MACVLAN_MODE_BRIDGE); + break; + } + case NM_LINK_TYPE_MACVTAP: { + const NMPlatformLnkMacvtap *plnk = &lnk->lnk_macvlan; + + g_assert (plnk == nm_platform_link_get_lnk_macvtap (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->no_promisc, ==, FALSE); + g_assert_cmpint (plnk->mode, ==, MACVLAN_MODE_PRIVATE); + break; + } + case NM_LINK_TYPE_SIT: { + const NMPlatformLnkSit *plnk = &lnk->lnk_sit; + + g_assert (plnk == nm_platform_link_get_lnk_sit (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->parent_ifindex, ==, ifindex_parent); + nmtst_assert_ip4_address (plnk->local, "192.168.200.1"); + nmtst_assert_ip4_address (plnk->remote, "172.25.100.14"); + g_assert_cmpint (plnk->ttl, ==, 0); + g_assert_cmpint (plnk->tos, ==, 31); + g_assert_cmpint (plnk->path_mtu_discovery, ==, FALSE); + break; + } + case NM_LINK_TYPE_VLAN: { + const NMPlatformLnkVlan *plnk = &lnk->lnk_vlan; + + g_assert (plnk == nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->id, ==, 1242); + break; + } + case NM_LINK_TYPE_VXLAN: { + const NMPlatformLnkVxlan *plnk = &lnk->lnk_vxlan; + + g_assert (plnk == nm_platform_link_get_lnk_vxlan (NM_PLATFORM_GET, ifindex, NULL)); + g_assert_cmpint (plnk->parent_ifindex, !=, 0); + g_assert_cmpint (plnk->tos, ==, 0); + g_assert_cmpint (plnk->learning, ==, TRUE); + g_assert_cmpint (plnk->limit, ==, 0); + g_assert_cmpint (plnk->proxy, ==, FALSE); + g_assert_cmpint (plnk->rsc, ==, FALSE); + g_assert_cmpint (plnk->l2miss, ==, FALSE); + g_assert_cmpint (plnk->l3miss, ==, FALSE); + + switch (test_data->test_mode) { + case 0: + g_assert_cmpint (plnk->id, ==, 42); + nmtst_assert_ip4_address (plnk->local, "23.1.2.164"); + nmtst_assert_ip4_address (plnk->group, "239.1.2.134"); + nmtst_assert_ip6_address (&plnk->group6, "::"); + nmtst_assert_ip6_address (&plnk->local6, "::"); + g_assert_cmpint (plnk->ttl, ==, 0); + g_assert_cmpint (plnk->ageing, ==, 1245); + g_assert_cmpint (plnk->dst_port, ==, 4789); + if ( plnk->src_port_min != 0 + || plnk->src_port_max != 0) { + /* on some kernels, omiting the port range results in setting + * following default port range. */ + g_assert_cmpint (plnk->src_port_min, ==, 32768); + g_assert_cmpint (plnk->src_port_max, ==, 61000); + } + break; + case 1: + g_assert_cmpint (plnk->id, ==, 11214423); + nmtst_assert_ip4_address (plnk->local, "0.0.0.0"); + nmtst_assert_ip4_address (plnk->group, "0.0.0.0"); + nmtst_assert_ip6_address (&plnk->group6, "ff0e::115"); + nmtst_assert_ip6_address (&plnk->local6, "1:2:3:4:334:23::23"); + g_assert_cmpint (plnk->ageing, ==, 3245); + g_assert_cmpint (plnk->dst_port, ==, 57412); + g_assert_cmpint (plnk->ttl, ==, 32); + g_assert_cmpint (plnk->src_port_min, ==, 1000); + g_assert_cmpint (plnk->src_port_max, ==, 1003); + break; + } + break; + } + default: + g_assert_not_reached (); + } + } + + nmtstp_link_del (-1, ifindex, DEVICE_NAME); +out_delete_parent: + nmtstp_link_del (-1, ifindex_parent, PARENT_NAME); +} + +static void +test_software_detect_add (const char *testpath, + NMLinkType link_type, + int test_mode) +{ + TestAddSoftwareDetectData *test_data; + char *path; + + test_data = g_new0 (TestAddSoftwareDetectData, 1); + test_data->link_type = link_type; + test_data->test_mode = test_mode; + test_data->external_command = TRUE; + + path = g_strdup_printf ("%s/external", testpath); + g_test_add_data_func_full (path, test_data, test_software_detect, g_free); + g_free (path); + + test_data = g_new0 (TestAddSoftwareDetectData, 1); + test_data->link_type = link_type; + test_data->test_mode = test_mode; + test_data->external_command = FALSE; + + path = g_strdup_printf ("%s/platform", testpath); + g_test_add_data_func_full (path, test_data, test_software_detect, g_free); + g_free (path); + + test_data = g_new0 (TestAddSoftwareDetectData, 1); + test_data->link_type = link_type; + test_data->test_mode = test_mode; + test_data->external_command = -1; + + path = g_strdup_printf ("%s/random", testpath); + g_test_add_data_func_full (path, test_data, test_software_detect, g_free); + g_free (path); +} + +/*****************************************************************************/ + +static void +_assert_xgress_qos_mappings_impl (int ifindex, + gboolean is_ingress_map , + int n_entries, + int n, + ...) +{ + const NMPlatformLink *plink; + const NMPObject *lnk; + guint n_map; + const NMVlanQosMapping *map; + va_list ap; + guint i; + + lnk = nm_platform_link_get_lnk (NM_PLATFORM_GET, ifindex, NM_LINK_TYPE_VLAN, &plink); + + g_assert (plink); + g_assert_cmpint (plink->ifindex, ==, ifindex); + g_assert (lnk); + g_assert (&lnk->lnk_vlan == nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, NULL)); + + if (nmtst_is_debug ()) + nmtstp_run_command_check ("ip -d link show %s", plink->name); + + if (is_ingress_map) { + map = lnk->_lnk_vlan.ingress_qos_map; + n_map = lnk->_lnk_vlan.n_ingress_qos_map; + } else { + map = lnk->_lnk_vlan.egress_qos_map; + n_map = lnk->_lnk_vlan.n_egress_qos_map; + } + + if (n_entries != -1) + g_assert_cmpint (n_map, ==, n_entries); + + for (i = 0; i < n_map; i++) { + if (is_ingress_map) { + g_assert_cmpint (map[i].from, >=, 0); + g_assert_cmpint (map[i].from, <=, 7); + } + if (i > 0) + g_assert_cmpint (map[i - 1].from, <, map[i].from); + } + + va_start (ap, n); + for (; n > 0; n--) { + gboolean found = FALSE; + guint from = va_arg (ap, guint); + guint to = va_arg (ap, guint); + + for (i = 0; i < n_map; i++) { + if (map[i].from == from) { + g_assert (!found); + found = TRUE; + + g_assert (map[i].to == to); + } + } + g_assert (found); + } + va_end (ap); +} +#define _assert_xgress_qos_mappings(ifindex, is_ingress_map, n_entries, ...) \ + _assert_xgress_qos_mappings_impl ((ifindex), (is_ingress_map), (n_entries), \ + (G_STATIC_ASSERT_EXPR ((NM_NARG (__VA_ARGS__) % 2) == 0), NM_NARG (__VA_ARGS__) / 2), \ + __VA_ARGS__) +#define _assert_ingress_qos_mappings(ifindex, n_entries, ...) _assert_xgress_qos_mappings (ifindex, TRUE, n_entries, __VA_ARGS__) +#define _assert_egress_qos_mappings(ifindex, n_entries, ...) _assert_xgress_qos_mappings (ifindex, FALSE, n_entries, __VA_ARGS__) + +static void +_assert_vlan_flags (int ifindex, NMVlanFlags flags) +{ + const NMPlatformLnkVlan *plnk; + + plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, NULL); + g_assert (plnk); + g_assert_cmpint (plnk->flags, ==, flags); +} + +static void +test_vlan_set_xgress (void) +{ + int ifindex, ifindex_parent; + + nmtstp_run_command_check ("ip link add %s type dummy", PARENT_NAME); + ifindex_parent = nmtstp_assert_wait_for_link (PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex; + + nmtstp_run_command_check ("ip link add name %s link %s type vlan id 1245", DEVICE_NAME, PARENT_NAME); + ifindex = nmtstp_assert_wait_for_link (DEVICE_NAME, NM_LINK_TYPE_VLAN, 100)->ifindex; + + /* ingress-qos-map */ + + g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 4, 5)); + _assert_ingress_qos_mappings (ifindex, 1, + 4, 5); + + g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 3, 7)); + _assert_ingress_qos_mappings (ifindex, 2, + 3, 7, + 4, 5); + + g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 3, 8)); + _assert_ingress_qos_mappings (ifindex, 2, + 3, 8, + 4, 5); + + g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, 4)); + _assert_ingress_qos_mappings (ifindex, 3, + 0, 4, + 3, 8, + 4, 5); + + g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, G_MAXUINT32)); + _assert_ingress_qos_mappings (ifindex, 3, + 0, G_MAXUINT32, + 3, 8, + 4, 5); + + g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, G_MAXUINT32 - 1)); + _assert_ingress_qos_mappings (ifindex, 3, + 0, G_MAXUINT32 - 1, + 3, 8, + 4, 5); + + g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, 5)); + _assert_ingress_qos_mappings (ifindex, 3, + 0, 5, + 3, 8, + 4, 5); + + g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, 5)); + _assert_ingress_qos_mappings (ifindex, 3, + 0, 5, + 3, 8, + 4, 5); + + /* Set invalid values: */ + g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 8, 3)); + _assert_ingress_qos_mappings (ifindex, 3, + 0, 5, + 3, 8, + 4, 5); + + g_assert (nm_platform_link_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 9, 4)); + _assert_ingress_qos_mappings (ifindex, 3, + 0, 5, + 3, 8, + 4, 5); + + /* egress-qos-map */ + + g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 7, 3)); + _assert_egress_qos_mappings (ifindex, 1, + 7, 3); + + g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 8, 4)); + _assert_egress_qos_mappings (ifindex, 2, + 7, 3, + 8, 4); + + g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 0, 4)); + _assert_egress_qos_mappings (ifindex, 3, + 0, 4, + 7, 3, + 8, 4); + + g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 1, 4)); + _assert_egress_qos_mappings (ifindex, 4, + 0, 4, + 1, 4, + 7, 3, + 8, 4); + + g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 1, 5)); + _assert_egress_qos_mappings (ifindex, 4, + 0, 4, + 1, 5, + 7, 3, + 8, 4); + + g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 9, 5)); + _assert_egress_qos_mappings (ifindex, 5, + 0, 4, + 1, 5, + 7, 3, + 8, 4, + 9, 5); + + g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 8, 5)); + _assert_egress_qos_mappings (ifindex, 5, + 0, 4, + 1, 5, + 7, 3, + 8, 5, + 9, 5); + + g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 8, 0)); + _assert_egress_qos_mappings (ifindex, 4, + 0, 4, + 1, 5, + 7, 3, + 9, 5); + + g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 0, 0)); + _assert_egress_qos_mappings (ifindex, 3, + 1, 5, + 7, 3, + 9, 5); + + g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 100, 4)); + _assert_egress_qos_mappings (ifindex, 4, + 1, 5, + 7, 3, + 9, 5, + 100, 4); + + g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, G_MAXUINT32, 4)); + _assert_egress_qos_mappings (ifindex, 5, + 1, 5, + 7, 3, + 9, 5, + 100, 4, + G_MAXUINT32, 4); + + g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, G_MAXUINT32, 8)); + _assert_egress_qos_mappings (ifindex, 5, + 1, 5, + 7, 3, + 9, 5, + 100, 4, + G_MAXUINT32, 4); + + g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, G_MAXUINT32, 0)); + _assert_egress_qos_mappings (ifindex, 4, + 1, 5, + 7, 3, + 9, 5, + 100, 4); + + g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 100, 0)); + _assert_egress_qos_mappings (ifindex, 3, + 1, 5, + 7, 3, + 9, 5); + + g_assert (nm_platform_link_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 1, 0)); + _assert_egress_qos_mappings (ifindex, 2, + 7, 3, + 9, 5); + + { + const NMVlanQosMapping ingress_map[] = { + { .from = 1, .to = 5 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + TRUE, + ingress_map, + G_N_ELEMENTS (ingress_map), + FALSE, + NULL, + 0)); + _assert_ingress_qos_mappings (ifindex, 1, + 1, 5); + } + + { + const NMVlanQosMapping ingress_map[] = { + { .from = 3, .to = 5 }, + { .from = 7, .to = 1655 }, + { .from = 7, .to = 17655 }, + { .from = 5, .to = 754 }, + { .from = 4, .to = 12 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + TRUE, + ingress_map, + G_N_ELEMENTS (ingress_map), + FALSE, + NULL, + 0)); + _assert_ingress_qos_mappings (ifindex, 4, + 3, 5, + 4, 12, + 7, 17655, + 5, 754); + } + + { + const NMVlanQosMapping ingress_map[] = { + { .from = 3, .to = 18 }, + { .from = 6, .to = 121 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + FALSE, + ingress_map, + G_N_ELEMENTS (ingress_map), + FALSE, + NULL, + 0)); + _assert_ingress_qos_mappings (ifindex, 5, + 3, 18, + 4, 12, + 6, 121, + 7, 17655, + 5, 754); + } + + { + const NMVlanQosMapping ingress_map[] = { + { .from = 3, .to = 0 }, + { .from = 6, .to = 7 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + TRUE, + ingress_map, + G_N_ELEMENTS (ingress_map), + FALSE, + NULL, + 0)); + _assert_ingress_qos_mappings (ifindex, 1, + 6, 7); + } + + + { + const NMVlanQosMapping ingress_map[] = { + { .from = 1, .to = 5 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + TRUE, + ingress_map, + G_N_ELEMENTS (ingress_map), + FALSE, + NULL, + 0)); + _assert_ingress_qos_mappings (ifindex, 1, + 1, 5); + } + + { + const NMVlanQosMapping egress_map[] = { + { .from = 5, .to = 1 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + FALSE, + NULL, + 0, + TRUE, + egress_map, + G_N_ELEMENTS (egress_map))); + _assert_egress_qos_mappings (ifindex, 1, + 5, 1); + } + + { + const NMVlanQosMapping egress_map[] = { + { .from = 5, .to = 3 }, + { .from = 1655, .to = 5 }, + { .from = 1655, .to = 7 }, + { .from = G_MAXUINT32, .to = 6 }, + { .from = G_MAXUINT32, .to = 8 }, + { .from = 754, .to = 4 }, + { .from = 3, .to = 2 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + FALSE, + NULL, + 0, + TRUE, + egress_map, + G_N_ELEMENTS (egress_map))); + _assert_egress_qos_mappings (ifindex, 5, + 3, 2, + 5, 3, + 754, 4, + 1655, 7, + G_MAXUINT32, 6); + } + + { + const NMVlanQosMapping egress_map[] = { + { .from = 754, .to = 3 }, + { .from = 755, .to = 8 }, + { .from = 1655, .to = 0 }, + { .from = 6, .to = 1 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + FALSE, + NULL, + 0, + FALSE, + egress_map, + G_N_ELEMENTS (egress_map))); + _assert_egress_qos_mappings (ifindex, 5, + 3, 2, + 5, 3, + 6, 1, + 754, 3, + G_MAXUINT32, 6); + } + + { + const NMVlanQosMapping egress_map[] = { + { .from = 6, .to = 0 }, + { .from = 3, .to = 4 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + FALSE, + NULL, + 0, + TRUE, + egress_map, + G_N_ELEMENTS (egress_map))); + _assert_egress_qos_mappings (ifindex, 1, + 3, 4); + } + + { + const NMVlanQosMapping egress_map[] = { + { .from = 1, .to = 5 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + 0, + 0, + FALSE, + NULL, + 0, + TRUE, + egress_map, + G_N_ELEMENTS (egress_map))); + _assert_egress_qos_mappings (ifindex, 1, + 1, 5); + } + + { + const NMVlanQosMapping ingress_map[] = { + { .from = 6, .to = 145 }, + { .from = 4, .to = 1 }, + { .from = 6, .to = 12 }, + }; + const NMVlanQosMapping egress_map[] = { + { .from = 1, .to = 5 }, + { .from = 3232, .to = 7 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + NM_VLAN_FLAG_REORDER_HEADERS | NM_VLAN_FLAG_GVRP, + NM_VLAN_FLAG_REORDER_HEADERS, + TRUE, + ingress_map, + G_N_ELEMENTS (ingress_map), + TRUE, + egress_map, + G_N_ELEMENTS (egress_map))); + _assert_ingress_qos_mappings (ifindex, 2, + 4, 1, + 6, 12); + _assert_egress_qos_mappings (ifindex, 2, + 1, 5, + 3232, 7); + _assert_vlan_flags (ifindex, NM_VLAN_FLAG_REORDER_HEADERS); + } + + { + const NMVlanQosMapping ingress_map[] = { + { .from = 6, .to = 145 }, + { .from = 4, .to = 1 }, + { .from = 6, .to = 12 }, + }; + const NMVlanQosMapping egress_map[] = { + { .from = 1, .to = 7 }, + { .from = 64, .to = 10 }, + { .from = 64, .to = 10 }, + { .from = 64, .to = 10 }, + { .from = 64, .to = 10 }, + { .from = 3232, .to = 0 }, + { .from = 64, .to = 4 }, + }; + + g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET, + ifindex, + NM_VLAN_FLAG_GVRP, + NM_VLAN_FLAG_GVRP, + FALSE, + ingress_map, + G_N_ELEMENTS (ingress_map), + FALSE, + egress_map, + G_N_ELEMENTS (egress_map))); + _assert_ingress_qos_mappings (ifindex, 2, + 4, 1, + 6, 12); + _assert_egress_qos_mappings (ifindex, 2, + 1, 7, + 64, 4); + _assert_vlan_flags (ifindex, NM_VLAN_FLAG_REORDER_HEADERS | NM_VLAN_FLAG_GVRP); + } + + nmtstp_link_del (-1, ifindex, DEVICE_NAME); + nmtstp_link_del (-1, ifindex_parent, PARENT_NAME); +} + +/*****************************************************************************/ + +static void +test_create_many_links_do (guint n_devices) +{ + gint64 time, start_time = nm_utils_get_monotonic_timestamp_ns (); + guint i; + char name[64]; + const NMPlatformLink *pllink; + gs_unref_array GArray *ifindexes = g_array_sized_new (FALSE, FALSE, sizeof (int), n_devices); + const gint EX = ((int) (nmtst_get_rand_int () % 4)) - 1; + + g_assert (EX >= -1 && EX <= 2); + + _LOGI (">>> create devices (EX=%d)...", EX); + + for (i = 0; i < n_devices; i++) { + nm_sprintf_buf (name, "t-%05u", i); + if (EX == 2) { + /* This mode is different from letting nmtstp_link_dummy_add() + * because in this case we don't process any platform events + * while adding all the links. */ + nmtstp_run_command_check ("ip link add %s type dummy", name); + } else + nmtstp_link_dummy_add (EX, name); + } + + _LOGI (">>> process events after creating devices..."); + + nm_platform_process_events (NM_PLATFORM_GET); + + _LOGI (">>> check devices..."); + + for (i = 0; i < n_devices; i++) { + nm_sprintf_buf (name, "t-%05u", i); + + pllink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, name); + g_assert (pllink); + g_assert_cmpint (pllink->type, ==, NM_LINK_TYPE_DUMMY); + g_assert_cmpstr (pllink->name, ==, name); + + g_array_append_val (ifindexes, pllink->ifindex); + } + + _LOGI (">>> delete devices..."); + + g_assert_cmpint (ifindexes->len, ==, n_devices); + for (i = 0; i < n_devices; i++) { + nm_sprintf_buf (name, "t-%05u", i); + + if (EX == 2) + nmtstp_run_command_check ("ip link delete %s", name); + else + nmtstp_link_del (EX, g_array_index (ifindexes, int, i), name); + } + + _LOGI (">>> process events after deleting devices..."); + nm_platform_process_events (NM_PLATFORM_GET); + + time = nm_utils_get_monotonic_timestamp_ns () - start_time; + _LOGI (">>> finished in %ld.%09ld seconds", (long) (time / NM_UTILS_NS_PER_SECOND), (long) (time % NM_UTILS_NS_PER_SECOND)); +} + +static void +test_create_many_links (gconstpointer user_data) +{ + guint n_devices = GPOINTER_TO_UINT (user_data); + + if (n_devices > 100 && nmtst_test_quick ()) { + g_print ("Skipping test: don't run long running test %s (NMTST_DEBUG=slow)\n", str_if_set (g_get_prgname (), "test-link-linux")); + g_test_skip ("Skip long running test"); + return; + } + + test_create_many_links_do (n_devices); +} + +/*****************************************************************************/ + +static void +test_nl_bugs_veth (void) +{ + const char *IFACE_VETH0 = "nm-test-veth0"; + const char *IFACE_VETH1 = "nm-test-veth1"; + int ifindex_veth0, ifindex_veth1; + int i; + const NMPlatformLink *pllink_veth0, *pllink_veth1; + gs_free_error GError *error = NULL; + NMTstpNamespaceHandle *ns_handle = NULL; + + /* create veth pair. */ + nmtstp_run_command_check ("ip link add dev %s type veth peer name %s", IFACE_VETH0, IFACE_VETH1); + ifindex_veth0 = nmtstp_assert_wait_for_link (IFACE_VETH0, NM_LINK_TYPE_VETH, 100)->ifindex; + ifindex_veth1 = nmtstp_assert_wait_for_link (IFACE_VETH1, NM_LINK_TYPE_VETH, 100)->ifindex; + + /* assert that nm_platform_link_veth_get_properties() returns the expected peer ifindexes. */ + g_assert (nm_platform_link_veth_get_properties (NM_PLATFORM_GET, ifindex_veth0, &i)); + g_assert_cmpint (i, ==, ifindex_veth1); + + g_assert (nm_platform_link_veth_get_properties (NM_PLATFORM_GET, ifindex_veth1, &i)); + g_assert_cmpint (i, ==, ifindex_veth0); + + /* assert that NMPlatformLink.parent is the peer-ifindex. */ + pllink_veth0 = nm_platform_link_get (NM_PLATFORM_GET, ifindex_veth0); + g_assert (pllink_veth0); + if (pllink_veth0->parent == 0) { + /* pre-4.1 kernels don't support exposing the veth peer as IFA_LINK. skip the remainder + * of the test. */ + goto out; + } + g_assert_cmpint (pllink_veth0->parent, ==, ifindex_veth1); + + + /* The following tests whether we have a workaround for kernel bug + * https://bugzilla.redhat.com/show_bug.cgi?id=1285827 in place. */ + pllink_veth1 = nm_platform_link_get (NM_PLATFORM_GET, ifindex_veth1); + g_assert (pllink_veth1); + g_assert_cmpint (pllink_veth1->parent, ==, ifindex_veth0); + + + /* move one veth peer to another namespace and check that the + * parent/IFLA_LINK of the remaining peer properly updates + * (https://bugzilla.redhat.com/show_bug.cgi?id=1262908). */ + ns_handle = nmtstp_namespace_create (CLONE_NEWNET, &error); + g_assert_no_error (error); + g_assert (ns_handle); + + nmtstp_run_command_check ("ip link set %s netns %ld", IFACE_VETH1, (long) nmtstp_namespace_handle_get_pid (ns_handle)); + NMTST_WAIT_ASSERT (100, { + nmtstp_wait_for_signal (50); + nm_platform_process_events (NM_PLATFORM_GET); + + pllink_veth1 = nm_platform_link_get (NM_PLATFORM_GET, ifindex_veth1); + pllink_veth0 = nm_platform_link_get (NM_PLATFORM_GET, ifindex_veth0); + if ( !pllink_veth1 + && pllink_veth0 + && pllink_veth0->parent == NM_PLATFORM_LINK_OTHER_NETNS) { + break; + } + }); + +out: + nmtstp_link_del (-1, ifindex_veth0, IFACE_VETH0); + g_assert (!nmtstp_link_get (ifindex_veth0, IFACE_VETH0)); + g_assert (!nmtstp_link_get (ifindex_veth1, IFACE_VETH1)); + nmtstp_namespace_handle_release (ns_handle); +} + +/*****************************************************************************/ + +static void +test_nl_bugs_spuroius_newlink (void) +{ + const char *IFACE_BOND0 = "nm-test-bond0"; + const char *IFACE_DUMMY0 = "nm-test-dummy0"; + int ifindex_bond0, ifindex_dummy0; + const NMPlatformLink *pllink; + gboolean wait_for_settle; + + /* see https://bugzilla.redhat.com/show_bug.cgi?id=1285719 */ + + nmtstp_run_command_check ("ip link add %s type dummy", IFACE_DUMMY0); + ifindex_dummy0 = nmtstp_assert_wait_for_link (IFACE_DUMMY0, NM_LINK_TYPE_DUMMY, 100)->ifindex; + + nmtstp_run_command_check ("ip link add %s type bond", IFACE_BOND0); + ifindex_bond0 = nmtstp_assert_wait_for_link (IFACE_BOND0, NM_LINK_TYPE_BOND, 100)->ifindex; + + nmtstp_link_set_updown (-1, ifindex_bond0, TRUE); + + nmtstp_run_command_check ("ip link set %s master %s", IFACE_DUMMY0, IFACE_BOND0); + NMTST_WAIT_ASSERT (100, { + nmtstp_wait_for_signal (50); + + pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex_dummy0); + g_assert (pllink); + if (pllink->master == ifindex_bond0) + break; + }); + + nmtstp_run_command_check ("ip link del %s", IFACE_BOND0); + + wait_for_settle = TRUE; + nmtstp_wait_for_signal (50); +again: + nm_platform_process_events (NM_PLATFORM_GET); + pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex_bond0); + g_assert (!pllink); + + if (wait_for_settle) { + wait_for_settle = FALSE; + NMTST_WAIT (300, { nmtstp_wait_for_signal (50); }); + goto again; + } + + g_assert (!nmtstp_link_get (ifindex_bond0, IFACE_BOND0)); + nmtstp_link_del (-1, ifindex_dummy0, IFACE_DUMMY0); +} + +/*****************************************************************************/ + +static void +test_nl_bugs_spuroius_dellink (void) +{ + const char *IFACE_BRIDGE0 = "nm-test-bridge0"; + const char *IFACE_DUMMY0 = "nm-test-dummy0"; + int ifindex_bridge0, ifindex_dummy0; + const NMPlatformLink *pllink; + gboolean wait_for_settle; + + /* see https://bugzilla.redhat.com/show_bug.cgi?id=1285719 */ + + nmtstp_run_command_check ("ip link add %s type dummy", IFACE_DUMMY0); + ifindex_dummy0 = nmtstp_assert_wait_for_link (IFACE_DUMMY0, NM_LINK_TYPE_DUMMY, 100)->ifindex; + + nmtstp_run_command_check ("ip link add %s type bridge", IFACE_BRIDGE0); + ifindex_bridge0 = nmtstp_assert_wait_for_link (IFACE_BRIDGE0, NM_LINK_TYPE_BRIDGE, 100)->ifindex; + + nmtstp_link_set_updown (-1, ifindex_bridge0, TRUE); + + nmtstp_run_command_check ("ip link set %s master %s", IFACE_DUMMY0, IFACE_BRIDGE0); + NMTST_WAIT_ASSERT (100, { + nmtstp_wait_for_signal (50); + + pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex_dummy0); + g_assert (pllink); + if (pllink->master == ifindex_bridge0) + break; + }); + + nm_platform_process_events (NM_PLATFORM_GET); + + nmtstp_run_command_check ("ip link set %s nomaster", IFACE_DUMMY0); + + wait_for_settle = TRUE; + nmtstp_wait_for_signal (50); +again: + nm_platform_process_events (NM_PLATFORM_GET); + pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex_bridge0); + g_assert (pllink); + pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex_dummy0); + g_assert (pllink); + g_assert_cmpint (pllink->parent, ==, 0); + + if (wait_for_settle) { + wait_for_settle = FALSE; + NMTST_WAIT (300, { nmtstp_wait_for_signal (50); }); + goto again; + } + + nmtstp_link_del (-1, ifindex_bridge0, IFACE_BRIDGE0); + nmtstp_link_del (-1, ifindex_dummy0, IFACE_DUMMY0); +} + +/*****************************************************************************/ + void init_tests (int *argc, char ***argv) { @@ -599,7 +1843,28 @@ setup_tests (void) 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); + g_test_add_func ("/link/software/bridge/addr", test_bridge_addr); - if (strcmp (g_type_name (G_TYPE_FROM_INSTANCE (nm_platform_get ())), "NMFakePlatform")) + if (nmtstp_is_root_test ()) { g_test_add_func ("/link/external", test_external); + + test_software_detect_add ("/link/software/detect/gre", NM_LINK_TYPE_GRE, 0); + test_software_detect_add ("/link/software/detect/ip6tnl", NM_LINK_TYPE_IP6TNL, 0); + test_software_detect_add ("/link/software/detect/ipip", NM_LINK_TYPE_IPIP, 0); + test_software_detect_add ("/link/software/detect/macvlan", NM_LINK_TYPE_MACVLAN, 0); + test_software_detect_add ("/link/software/detect/macvtap", NM_LINK_TYPE_MACVTAP, 0); + test_software_detect_add ("/link/software/detect/sit", NM_LINK_TYPE_SIT, 0); + test_software_detect_add ("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0); + test_software_detect_add ("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0); + test_software_detect_add ("/link/software/detect/vxlan/1", NM_LINK_TYPE_VXLAN, 1); + + g_test_add_func ("/link/software/vlan/set-xgress", test_vlan_set_xgress); + + g_test_add_data_func ("/link/create-many-links/20", GUINT_TO_POINTER (20), test_create_many_links); + g_test_add_data_func ("/link/create-many-links/1000", GUINT_TO_POINTER (1000), test_create_many_links); + + g_test_add_func ("/link/nl-bugs/veth", test_nl_bugs_veth); + g_test_add_func ("/link/nl-bugs/spurious-newlink", test_nl_bugs_spuroius_newlink); + g_test_add_func ("/link/nl-bugs/spurious-dellink", test_nl_bugs_spuroius_dellink); + } } diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c index 88bb0707..eba2383b 100644 --- a/src/platform/tests/test-nmp-object.c +++ b/src/platform/tests/test-nmp-object.c @@ -20,7 +20,7 @@ #include "nmp-object.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-test-utils.h" @@ -148,8 +148,8 @@ _nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, NMPCacheOpsType ops_type; NMPObject *obj2; gboolean was_visible; - auto_nmp_obj NMPObject *obj_clone = nmp_object_clone (obj, FALSE); - auto_nmp_obj NMPObject *new_clone = NULL; + nm_auto_nmpobj NMPObject *obj_clone = nmp_object_clone (obj, FALSE); + nm_auto_nmpobj NMPObject *new_clone = NULL; const NMPObject *obj_old; _NMPCacheUpdateData data = { .cache = cache, diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index cf322dec..60a0c15c 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -9,7 +9,7 @@ #define DEVICE_NAME "nm-test-device" static void -ip4_route_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, const NMPlatformIP4Route *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data) +ip4_route_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, const NMPlatformIP4Route *received, NMPlatformSignalChangeType change_type, SignalData *data) { g_assert (received); g_assert_cmpint (received->ifindex, ==, ifindex); @@ -25,11 +25,11 @@ ip4_route_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, c g_main_loop_quit (data->loop); data->received_count++; - debug ("Received signal '%s' %dth time.", data->name, data->received_count); + _LOGD ("Received signal '%s' %dth time.", data->name, data->received_count); } static void -ip6_route_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, const NMPlatformIP6Route *received, NMPlatformSignalChangeType change_type, NMPlatformReason reason, SignalData *data) +ip6_route_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, const NMPlatformIP6Route *received, NMPlatformSignalChangeType change_type, SignalData *data) { g_assert (received); g_assert_cmpint (received->ifindex, ==, ifindex); @@ -45,7 +45,7 @@ ip6_route_callback (NMPlatform *platform, NMPObjectType obj_type, int ifindex, c g_main_loop_quit (data->loop); data->received_count++; - debug ("Received signal '%s' %dth time.", data->name, data->received_count); + _LOGD ("Received signal '%s' %dth time.", data->name, data->received_count); } static void @@ -282,6 +282,31 @@ test_ip6_route (void) free_signal (route_removed); } +/*****************************************************************************/ + +static void +test_ip4_zero_gateway (void) +{ + int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME); + + nmtstp_run_command_check ("ip route add 1.2.3.1/32 via 0.0.0.0 dev %s", DEVICE_NAME); + nmtstp_run_command_check ("ip route add 1.2.3.2/32 dev %s", DEVICE_NAME); + + NMTST_WAIT_ASSERT (100, { + nmtstp_wait_for_signal (10); + if ( nm_platform_ip4_route_get (NM_PLATFORM_GET, ifindex, nmtst_inet4_from_string ("1.2.3.1"), 32, 0) + && nm_platform_ip4_route_get (NM_PLATFORM_GET, ifindex, nmtst_inet4_from_string ("1.2.3.2"), 32, 0)) + break; + }); + + nmtstp_run_command_check ("ip route flush dev %s", DEVICE_NAME); + + nmtstp_wait_for_signal (50); + nm_platform_process_events (NM_PLATFORM_GET); +} + +/*****************************************************************************/ + void init_tests (int *argc, char ***argv) { @@ -295,7 +320,7 @@ setup_tests (void) nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)); g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, DEVICE_NAME)); - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS); + g_assert (nm_platform_link_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL) == NM_PLATFORM_ERROR_SUCCESS); accept_signal (link_added); free_signal (link_added); @@ -304,4 +329,7 @@ setup_tests (void) g_test_add_func ("/route/ip4", test_ip4_route); g_test_add_func ("/route/ip6", test_ip6_route); g_test_add_func ("/route/ip4_metric0", test_ip4_route_metric0); + + if (nmtstp_is_root_test ()) + g_test_add_func ("/route/ip4_zero_gateway", test_ip4_zero_gateway); } diff --git a/src/platform/wifi/wifi-utils-nl80211.c b/src/platform/wifi/wifi-utils-nl80211.c index b31ffa1c..e05104f3 100644 --- a/src/platform/wifi/wifi-utils-nl80211.c +++ b/src/platform/wifi/wifi-utils-nl80211.c @@ -28,21 +28,208 @@ #include #include #include - -#include - -#include -#include -#include - +#include +#include #include +#include "nm-default.h" #include "wifi-utils-private.h" #include "wifi-utils-nl80211.h" #include "nm-platform.h" -#include "nm-logging.h" #include "nm-utils.h" + +/***************************************************************************** + * Copied from libnl3/genl: + *****************************************************************************/ + +static void * +genlmsg_put (struct nl_msg *msg, uint32_t port, uint32_t seq, int family, + int hdrlen, int flags, uint8_t cmd, uint8_t version) +{ + struct nlmsghdr *nlh; + struct genlmsghdr hdr = { + .cmd = cmd, + .version = version, + }; + + nlh = nlmsg_put (msg, port, seq, family, GENL_HDRLEN + hdrlen, flags); + if (nlh == NULL) + return NULL; + + memcpy (nlmsg_data (nlh), &hdr, sizeof (hdr)); + + return (char *) nlmsg_data (nlh) + GENL_HDRLEN; +} + +static void * +genlmsg_data (const struct genlmsghdr *gnlh) +{ + return ((unsigned char *) gnlh + GENL_HDRLEN); +} + +static void * +genlmsg_user_hdr (const struct genlmsghdr *gnlh) +{ + return genlmsg_data (gnlh); +} + +static struct genlmsghdr * +genlmsg_hdr (struct nlmsghdr *nlh) +{ + return nlmsg_data (nlh); +} + +static void * +genlmsg_user_data (const struct genlmsghdr *gnlh, const int hdrlen) +{ + return (char *) genlmsg_user_hdr (gnlh) + NLMSG_ALIGN (hdrlen); +} + +static struct nlattr * +genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen) +{ + return genlmsg_user_data (gnlh, hdrlen); +} + +static int +genlmsg_len (const struct genlmsghdr *gnlh) +{ + const struct nlmsghdr *nlh; + + nlh = (const struct nlmsghdr *) ((const unsigned char *) gnlh - NLMSG_HDRLEN); + return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN); +} + +static int +genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen) +{ + return genlmsg_len (gnlh) - NLMSG_ALIGN (hdrlen); +} + +static int +genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen) +{ + struct genlmsghdr *ghdr; + + if (!nlmsg_valid_hdr (nlh, GENL_HDRLEN)) + return 0; + + ghdr = nlmsg_data (nlh); + if (genlmsg_len (ghdr) < NLMSG_ALIGN (hdrlen)) + return 0; + + return 1; +} + +static int +genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[], + int maxtype, struct nla_policy *policy) +{ + struct genlmsghdr *ghdr; + + if (!genlmsg_valid_hdr (nlh, hdrlen)) + return -NLE_MSG_TOOSHORT; + + ghdr = nlmsg_data (nlh); + return nla_parse (tb, maxtype, genlmsg_attrdata (ghdr, hdrlen), + genlmsg_attrlen (ghdr, hdrlen), policy); +} + +/***************************************************************************** + * Reimplementation of libnl3/genl functions: + *****************************************************************************/ + +static int +probe_response (struct nl_msg *msg, void *arg) +{ + static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = { + [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, + [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING, + .maxlen = GENL_NAMSIZ }, + [CTRL_ATTR_VERSION] = { .type = NLA_U32 }, + [CTRL_ATTR_HDRSIZE] = { .type = NLA_U32 }, + [CTRL_ATTR_MAXATTR] = { .type = NLA_U32 }, + [CTRL_ATTR_OPS] = { .type = NLA_NESTED }, + [CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED }, + }; + struct nlattr *tb[CTRL_ATTR_MAX+1]; + struct nlmsghdr *nlh = nlmsg_hdr (msg); + gint32 *response_data = arg; + + if (genlmsg_parse (nlh, 0, tb, CTRL_ATTR_MAX, ctrl_policy)) + return NL_SKIP; + + if (tb[CTRL_ATTR_FAMILY_ID]) + *response_data = nla_get_u16 (tb[CTRL_ATTR_FAMILY_ID]); + + return NL_STOP; +} + +static int +genl_ctrl_resolve (struct nl_sock *sk, const char *name) +{ + struct nl_msg *msg; + struct nl_cb *cb, *orig; + int rc; + int result = -NLE_OBJ_NOTFOUND; + gint32 response_data = -1; + + if (!(orig = nl_socket_get_cb (sk))) + goto out; + + cb = nl_cb_clone (orig); + nl_cb_put (orig); + if (!cb) + goto out; + + msg = nlmsg_alloc (); + if (!msg) + goto out_cb_free; + + if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL, + 0, 0, CTRL_CMD_GETFAMILY, 1)) + goto out_msg_free; + + if (nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name) < 0) + goto out_msg_free; + + rc = nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, probe_response, &response_data); + if (rc < 0) + goto out_msg_free; + + rc = nl_send_auto_complete (sk, msg); + if (rc < 0) + goto out_msg_free; + + rc = nl_recvmsgs (sk, cb); + if (rc < 0) + goto out_msg_free; + + /* If search was successful, request may be ACKed after data */ + rc = nl_wait_for_ack (sk); + if (rc < 0) + goto out_msg_free; + + if (response_data > 0) + result = response_data; + +out_msg_free: + nlmsg_free (msg); +out_cb_free: + nl_cb_put (cb); +out: + if (result >= 0) + nm_log_dbg (LOGD_WIFI, "genl_ctrl_resolve: resolved \"%s\" as 0x%x", name, result); + else + nm_log_err (LOGD_WIFI, "genl_ctrl_resolve: failed resolve \"%s\"", name); + return result; +} + +/***************************************************************************** + * + *****************************************************************************/ + typedef struct { WifiData parent; struct nl_sock *nl_sock; @@ -144,7 +331,7 @@ _nl80211_send_and_recv (struct nl_sock *nl_sock, * 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) + genlmsg_hdr (nlmsg_hdr (msg))->cmd == NL80211_CMD_GET_SCAN) break; nm_log_warn (LOGD_WIFI, "nl_recvmsgs() error: (%d) %s", @@ -265,6 +452,24 @@ wifi_nl80211_set_mode (WifiData *data, const NM80211Mode mode) return FALSE; } +static gboolean +wifi_nl80211_set_powersave (WifiData *data, guint32 powersave) +{ + WifiDataNl80211 *nl80211 = (WifiDataNl80211 *) data; + struct nl_msg *msg; + int err; + + msg = nl80211_alloc_msg (nl80211, NL80211_CMD_SET_POWER_SAVE, 0); + NLA_PUT_U32 (msg, NL80211_ATTR_PS_STATE, + powersave == 1 ? NL80211_PS_ENABLED : NL80211_PS_DISABLED); + 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) @@ -273,7 +478,7 @@ nl80211_xbm_to_percent (gint32 xbm, guint32 divisor) #define SIGNAL_MAX_DBM -20 xbm /= divisor; - xbm = CLAMP(xbm, NOISE_FLOOR_DBM, SIGNAL_MAX_DBM); + 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)); @@ -353,7 +558,7 @@ nl80211_bss_dump_handler (struct nl_msg *msg, void *arg) if (bss[NL80211_BSS_BSSID] == NULL) return NL_SKIP; - memcpy(info->bssid, nla_data (bss[NL80211_BSS_BSSID]), ETH_ALEN); + 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]); @@ -370,7 +575,7 @@ nl80211_bss_dump_handler (struct nl_msg *msg, void *arg) guint8 *ssid; guint32 ssid_len; - find_ssid(nla_data (bss[NL80211_BSS_INFORMATION_ELEMENTS]), + 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)) { @@ -390,7 +595,7 @@ nl80211_get_bss_info (WifiDataNl80211 *nl80211, { struct nl_msg *msg; - memset(bss_info, 0, sizeof (*bss_info)); + memset (bss_info, 0, sizeof (*bss_info)); msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_SCAN, NLM_F_DUMP); @@ -424,24 +629,6 @@ wifi_nl80211_find_freq (WifiData *data, const guint32 *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, guint8 *out_bssid) { @@ -451,7 +638,7 @@ wifi_nl80211_get_bssid (WifiData *data, guint8 *out_bssid) nl80211_get_bss_info (nl80211, &bss_info); if (bss_info.valid) - memcpy(out_bssid, bss_info.bssid, ETH_ALEN); + memcpy (out_bssid, bss_info.bssid, ETH_ALEN); return bss_info.valid; } @@ -533,7 +720,7 @@ nl80211_get_ap_info (WifiDataNl80211 *nl80211, struct nl_msg *msg; struct nl80211_bss_info bss_info; - memset(sta_info, 0, sizeof (*sta_info)); + memset (sta_info, 0, sizeof (*sta_info)); nl80211_get_bss_info (nl80211, &bss_info); if (!bss_info.valid) @@ -621,7 +808,7 @@ nl80211_wowlan_handler (struct nl_msg *msg, void *arg) info->enabled = FALSE; - if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0), genlmsg_attrlen (gnlh, 0), NULL) < 0) return NL_SKIP; @@ -695,7 +882,7 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) G_STATIC_ASSERT (NL80211_FREQUENCY_ATTR_PASSIVE_SCAN != NL80211_FREQUENCY_ATTR_NO_IBSS); #endif - if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0), genlmsg_attrlen (gnlh, 0), NULL) < 0) return NL_SKIP; @@ -743,13 +930,13 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) 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) + NULL) < 0) return NL_SKIP; - nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], - rem_freq) { + 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); + nl_freq, freq_policy); if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) continue; @@ -767,7 +954,7 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg) NULL) < 0) return NL_SKIP; - nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], + 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); @@ -853,9 +1040,9 @@ wifi_nl80211_init (const char *iface, int ifindex) 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.set_powersave = wifi_nl80211_set_powersave; 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; @@ -868,7 +1055,7 @@ wifi_nl80211_init (const char *iface, int ifindex) if (nl80211->nl_sock == NULL) goto error; - if (genl_connect (nl80211->nl_sock)) + if (nl_connect (nl80211->nl_sock, NETLINK_GENERIC)) goto error; nl80211->id = genl_ctrl_resolve (nl80211->nl_sock, "nl80211"); @@ -886,22 +1073,22 @@ wifi_nl80211_init (const char *iface, int ifindex) 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); + "(%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); + "(%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); + "(%s): driver does not fully support nl80211, falling back to WEXT", + nl80211->parent.iface); goto error; } @@ -914,8 +1101,8 @@ wifi_nl80211_init (const char *iface, int ifindex) 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); + "(%s): driver reports no supported frequencies", + nl80211->parent.iface); goto error; } diff --git a/src/platform/wifi/wifi-utils-private.h b/src/platform/wifi/wifi-utils-private.h index aaedd5b7..21a4c57b 100644 --- a/src/platform/wifi/wifi-utils-private.h +++ b/src/platform/wifi/wifi-utils-private.h @@ -21,8 +21,8 @@ #ifndef __WIFI_UTILS_PRIVATE_H__ #define __WIFI_UTILS_PRIVATE_H__ -#include +#include "nm-default.h" #include "nm-dbus-interface.h" #include "wifi-utils.h" @@ -35,15 +35,15 @@ struct WifiData { gboolean (*set_mode) (WifiData *data, const NM80211Mode mode); + /* Set power saving mode on an interface */ + gboolean (*set_powersave) (WifiData *data, guint32 powersave); + /* 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); diff --git a/src/platform/wifi/wifi-utils-wext.c b/src/platform/wifi/wifi-utils-wext.c index 470b73d1..96bcf53d 100644 --- a/src/platform/wifi/wifi-utils-wext.c +++ b/src/platform/wifi/wifi-utils-wext.c @@ -28,11 +28,10 @@ #include #include -#include +#include "nm-default.h" #include "wifi-utils-private.h" #include "wifi-utils-wext.h" -#include "nm-logging.h" #include "nm-utils.h" #include "nm-platform-utils.h" @@ -45,7 +44,6 @@ #include #include - typedef struct { WifiData parent; int fd; @@ -166,6 +164,30 @@ wifi_wext_set_mode (WifiData *data, const NM80211Mode mode) return TRUE; } +static gboolean +wifi_wext_set_powersave (WifiData *data, guint32 powersave) +{ + WifiDataWext *wext = (WifiDataWext *) data; + struct iwreq wrq; + + memset (&wrq, 0, sizeof (struct iwreq)); + if (powersave == 1) { + wrq.u.power.flags = IW_POWER_ALL_R; + } else + wrq.u.power.disabled = 1; + + strncpy (wrq.ifr_name, wext->parent.iface, IFNAMSIZ); + if (ioctl (wext->fd, SIOCSIWPOWER, &wrq) < 0) { + if (errno != ENODEV) { + nm_log_err (LOGD_HW | LOGD_WIFI, "(%s): error setting powersave %" G_GUINT32_FORMAT, + wext->parent.iface, powersave); + } + return FALSE; + } + + return TRUE; +} + static guint32 wifi_wext_get_freq (WifiData *data) { @@ -200,36 +222,6 @@ wifi_wext_find_freq (WifiData *data, const guint32 *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, guint8 *out_bssid) { @@ -575,9 +567,9 @@ wifi_wext_init (const char *iface, int ifindex, gboolean check_scan) 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.set_powersave = wifi_wext_set_powersave; 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; diff --git a/src/platform/wifi/wifi-utils.c b/src/platform/wifi/wifi-utils.c index 068c404e..5f2f61b0 100644 --- a/src/platform/wifi/wifi-utils.c +++ b/src/platform/wifi/wifi-utils.c @@ -24,8 +24,8 @@ #include #include #include -#include +#include "nm-default.h" #include "wifi-utils.h" #include "wifi-utils-private.h" #include "wifi-utils-nl80211.h" @@ -98,6 +98,14 @@ wifi_utils_set_mode (WifiData *data, const NM80211Mode mode) return data->set_mode ? data->set_mode (data, mode) : TRUE; } +gboolean +wifi_utils_set_powersave (WifiData *data, guint32 powersave) +{ + g_return_val_if_fail (data != NULL, FALSE); + + return data->set_powersave ? data->set_powersave (data, powersave) : TRUE; +} + guint32 wifi_utils_get_freq (WifiData *data) { @@ -113,13 +121,6 @@ wifi_utils_find_freq (WifiData *data, const guint32 *freqs) 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, guint8 *out_bssid) { diff --git a/src/platform/wifi/wifi-utils.h b/src/platform/wifi/wifi-utils.h index 588386ab..21dac9e9 100644 --- a/src/platform/wifi/wifi-utils.h +++ b/src/platform/wifi/wifi-utils.h @@ -23,8 +23,8 @@ #define __WIFI_UTILS_H__ #include -#include +#include "nm-default.h" #include "nm-dbus-interface.h" typedef struct WifiData WifiData; @@ -48,9 +48,6 @@ guint32 wifi_utils_get_freq (WifiData *data); * Frequencies are specified in MHz. */ guint32 wifi_utils_find_freq (WifiData *data, const guint32 *freqs); -/* Caller must free returned byte array */ -GByteArray *wifi_utils_get_ssid (WifiData *data); - /* out_bssid must be ETH_ALEN bytes */ gboolean wifi_utils_get_bssid (WifiData *data, guint8 *out_bssid); @@ -66,6 +63,8 @@ gboolean wifi_utils_indicate_addressing_running (WifiData *data, gboolean runnin /* Returns true if WoWLAN is enabled on device */ gboolean wifi_utils_get_wowlan (WifiData *data); +gboolean wifi_utils_set_powersave (WifiData *data, guint32 powersave); + /* OLPC Mesh-only functions */ guint32 wifi_utils_get_mesh_channel (WifiData *data); diff --git a/src/ppp-manager/Makefile.am b/src/ppp-manager/Makefile.am index 5b1edc29..5cf908df 100644 --- a/src/ppp-manager/Makefile.am +++ b/src/ppp-manager/Makefile.am @@ -1,12 +1,13 @@ if WITH_PPP AM_CPPFLAGS = \ - -I${top_srcdir}/include \ - -I${top_builddir}/include \ + -I${top_srcdir}/shared \ + -I${top_builddir}/shared \ -I${top_srcdir}/libnm-core \ + -I${top_srcdir}/src \ -I${top_builddir}/libnm-core \ -DG_LOG_DOMAIN=\""nm-pppd-plugin"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) diff --git a/src/ppp-manager/Makefile.in b/src/ppp-manager/Makefile.in index 338dcff7..50e84429 100644 --- a/src/ppp-manager/Makefile.in +++ b/src/ppp-manager/Makefile.in @@ -232,7 +232,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -244,8 +243,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -255,6 +252,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -309,16 +307,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -355,6 +350,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -383,7 +380,6 @@ 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@ @@ -398,6 +394,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -458,6 +456,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -465,6 +464,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -481,12 +481,13 @@ with_netconfig = @with_netconfig@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ @WITH_PPP_TRUE@AM_CPPFLAGS = \ -@WITH_PPP_TRUE@ -I${top_srcdir}/include \ -@WITH_PPP_TRUE@ -I${top_builddir}/include \ +@WITH_PPP_TRUE@ -I${top_srcdir}/shared \ +@WITH_PPP_TRUE@ -I${top_builddir}/shared \ @WITH_PPP_TRUE@ -I${top_srcdir}/libnm-core \ +@WITH_PPP_TRUE@ -I${top_srcdir}/src \ @WITH_PPP_TRUE@ -I${top_builddir}/libnm-core \ @WITH_PPP_TRUE@ -DG_LOG_DOMAIN=\""nm-pppd-plugin"\" \ -@WITH_PPP_TRUE@ -DNETWORKMANAGER_COMPILATION \ +@WITH_PPP_TRUE@ -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ @WITH_PPP_TRUE@ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ @WITH_PPP_TRUE@ $(GLIB_CFLAGS) diff --git a/src/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c index d27b262e..10bc0fec 100644 --- a/src/ppp-manager/nm-ppp-manager.c +++ b/src/ppp-manager/nm-ppp-manager.c @@ -42,30 +42,13 @@ #include #include +#include "nm-default.h" #include "NetworkManagerUtils.h" -#include "nm-glib-compat.h" #include "nm-ppp-manager.h" -#include "nm-dbus-manager.h" -#include "nm-logging.h" #include "nm-platform.h" #include "nm-core-internal.h" -static void impl_ppp_manager_need_secrets (NMPPPManager *manager, - DBusGMethodInvocation *context); - -static gboolean impl_ppp_manager_set_state (NMPPPManager *manager, - guint32 state, - GError **err); - -static gboolean impl_ppp_manager_set_ip4_config (NMPPPManager *manager, - GHashTable *config, - GError **err); - -static gboolean impl_ppp_manager_set_ip6_config (NMPPPManager *manager, - GHashTable *config, - GError **err); - -#include "nm-ppp-manager-glue.h" +#include "nmdbus-ppp-manager.h" static void _ppp_cleanup (NMPPPManager *manager); static void _ppp_kill (NMPPPManager *manager); @@ -75,13 +58,12 @@ static void _ppp_kill (NMPPPManager *manager); typedef struct { GPid pid; - char *dbus_path; char *parent_iface; NMActRequest *act_req; - DBusGMethodInvocation *pending_secrets_context; - guint32 secrets_id; + GDBusMethodInvocation *pending_secrets_context; + NMActRequestGetSecretsCallId secrets_id; const char *secrets_setting_name; guint32 ppp_watch_id; @@ -95,7 +77,7 @@ typedef struct { #define NM_PPP_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_PPP_MANAGER, NMPPPManagerPrivate)) -G_DEFINE_TYPE (NMPPPManager, nm_ppp_manager, G_TYPE_OBJECT) +G_DEFINE_TYPE (NMPPPManager, nm_ppp_manager, NM_TYPE_EXPORTED_OBJECT) enum { STATE_CHANGED, @@ -120,20 +102,6 @@ nm_ppp_manager_init (NMPPPManager *manager) NM_PPP_MANAGER_GET_PRIVATE (manager)->monitor_fd = -1; } -static void -constructed (GObject *object) -{ - NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (object); - DBusGConnection *connection; - static guint32 counter = 0; - - priv->dbus_path = g_strdup_printf (NM_DBUS_PATH "/PPP/%d", counter++); - connection = nm_dbus_manager_get_connection (nm_dbus_manager_get ()); - dbus_g_connection_register_g_object (connection, priv->dbus_path, object); - - G_OBJECT_CLASS (nm_ppp_manager_parent_class)->constructed (object); -} - static void dispose (GObject *object) { @@ -191,68 +159,6 @@ get_property (GObject *object, guint prop_id, } } -static void -nm_ppp_manager_class_init (NMPPPManagerClass *manager_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (manager_class); - - g_type_class_add_private (manager_class, sizeof (NMPPPManagerPrivate)); - - object_class->constructed = constructed; - object_class->dispose = dispose; - object_class->finalize = finalize; - object_class->get_property = get_property; - object_class->set_property = set_property; - - /* Properties */ - g_object_class_install_property - (object_class, PROP_PARENT_IFACE, - g_param_spec_string (NM_PPP_MANAGER_PARENT_IFACE, "", "", - NULL, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - /* signals */ - signals[STATE_CHANGED] = - g_signal_new ("state-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMPPPManagerClass, state_changed), - NULL, NULL, NULL, - G_TYPE_NONE, 1, - G_TYPE_UINT); - - signals[IP4_CONFIG] = - g_signal_new ("ip4-config", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMPPPManagerClass, ip4_config), - NULL, NULL, NULL, - G_TYPE_NONE, 2, - G_TYPE_STRING, - G_TYPE_OBJECT); - - signals[IP6_CONFIG] = - g_signal_new ("ip6-config", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMPPPManagerClass, ip6_config), - NULL, NULL, NULL, - G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_OBJECT); - - signals[STATS] = - g_signal_new ("stats", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMPPPManagerClass, stats), - NULL, NULL, NULL, - G_TYPE_NONE, 2, - G_TYPE_UINT, G_TYPE_UINT); - - dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (manager_class), - &dbus_glib_nm_ppp_manager_object_info); -} - NMPPPManager * nm_ppp_manager_new (const char *iface) { @@ -315,11 +221,8 @@ static void remove_timeout_handler (NMPPPManager *manager) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); - - if (priv->ppp_timeout_handler) { - g_source_remove (priv->ppp_timeout_handler); - priv->ppp_timeout_handler = 0; - } + + nm_clear_g_source (&priv->ppp_timeout_handler); } static void @@ -327,11 +230,10 @@ cancel_get_secrets (NMPPPManager *self) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); - if (priv->secrets_id) { + if (priv->secrets_id) nm_act_request_cancel_secrets (priv->act_req, priv->secrets_id); - priv->secrets_id = 0; - } - priv->secrets_setting_name = NULL; + + g_return_if_fail (!priv->secrets_id && !priv->secrets_setting_name); } static gboolean @@ -395,8 +297,8 @@ extract_details_from_connection (NMConnection *connection, static void ppp_secrets_cb (NMActRequest *req, - guint32 call_id, - NMConnection *connection, + NMActRequestGetSecretsCallId call_id, + NMSettingsConnection *settings_connection, /* unused (we pass NULL here) */ GError *error, gpointer user_data) { @@ -405,21 +307,26 @@ ppp_secrets_cb (NMActRequest *req, const char *username = NULL; const char *password = NULL; GError *local = NULL; + NMConnection *applied_connection; g_return_if_fail (priv->pending_secrets_context != NULL); g_return_if_fail (req == priv->act_req); g_return_if_fail (call_id == priv->secrets_id); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + goto out; + if (error) { nm_log_warn (LOGD_PPP, "%s", error->message); - dbus_g_method_return_error (priv->pending_secrets_context, error); + g_dbus_method_invocation_return_gerror (priv->pending_secrets_context, error); goto out; } - if (!extract_details_from_connection (connection, priv->secrets_setting_name, &username, &password, &local)) { + applied_connection = nm_act_request_get_applied_connection (req); + + if (!extract_details_from_connection (applied_connection, priv->secrets_setting_name, &username, &password, &local)) { nm_log_warn (LOGD_PPP, "%s", local->message); - dbus_g_method_return_error (priv->pending_secrets_context, local); - g_clear_error (&local); + g_dbus_method_invocation_take_error (priv->pending_secrets_context, local); goto out; } @@ -429,20 +336,22 @@ ppp_secrets_cb (NMActRequest *req, * against libnm just to parse this. So instead, let's just send what * it needs. */ - dbus_g_method_return (priv->pending_secrets_context, username, password); + g_dbus_method_invocation_return_value ( + priv->pending_secrets_context, + g_variant_new ("(ss)", username ? username : "", password ? password : "")); out: priv->pending_secrets_context = NULL; - priv->secrets_id = 0; + priv->secrets_id = NULL; priv->secrets_setting_name = NULL; } static void impl_ppp_manager_need_secrets (NMPPPManager *manager, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); - NMConnection *connection; + NMConnection *applied_connection; const char *username = NULL; const char *password = NULL; guint32 tries; @@ -450,20 +359,20 @@ impl_ppp_manager_need_secrets (NMPPPManager *manager, GError *error = NULL; NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; - connection = nm_act_request_get_connection (priv->act_req); + nm_active_connection_clear_secrets (NM_ACTIVE_CONNECTION (priv->act_req)); - nm_connection_clear_secrets (connection); - priv->secrets_setting_name = nm_connection_need_secrets (connection, &hints); + applied_connection = nm_act_request_get_applied_connection (priv->act_req); + + priv->secrets_setting_name = nm_connection_need_secrets (applied_connection, &hints); if (!priv->secrets_setting_name) { /* Use existing secrets from the connection */ - if (extract_details_from_connection (connection, NULL, &username, &password, &error)) { + if (extract_details_from_connection (applied_connection, NULL, &username, &password, &error)) { /* Send existing secrets to the PPP plugin */ priv->pending_secrets_context = context; - ppp_secrets_cb (priv->act_req, priv->secrets_id, connection, NULL, manager); + ppp_secrets_cb (priv->act_req, priv->secrets_id, NULL, NULL, manager); } else { nm_log_warn (LOGD_PPP, "%s", error->message); - dbus_g_method_return_error (priv->pending_secrets_context, error); - g_clear_error (&error); + g_dbus_method_invocation_take_error (priv->pending_secrets_context, error); } return; } @@ -472,7 +381,7 @@ impl_ppp_manager_need_secrets (NMPPPManager *manager, * appear to ask a few times when they actually don't even care what you * pass back. */ - tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (connection), PPP_MANAGER_SECRET_TRIES)); + tries = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (applied_connection), PPP_MANAGER_SECRET_TRIES)); if (tries > 1) flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; @@ -482,88 +391,86 @@ impl_ppp_manager_need_secrets (NMPPPManager *manager, hints ? g_ptr_array_index (hints, 0) : NULL, ppp_secrets_cb, manager); - g_object_set_data (G_OBJECT (connection), PPP_MANAGER_SECRET_TRIES, GUINT_TO_POINTER (++tries)); + g_object_set_data (G_OBJECT (applied_connection), PPP_MANAGER_SECRET_TRIES, GUINT_TO_POINTER (++tries)); priv->pending_secrets_context = context; if (hints) g_ptr_array_free (hints, TRUE); } -static gboolean impl_ppp_manager_set_state (NMPPPManager *manager, - guint32 state, - GError **err) +static void +impl_ppp_manager_set_state (NMPPPManager *manager, + GDBusMethodInvocation *context, + guint32 state) { g_signal_emit (manager, signals[STATE_CHANGED], 0, state); - return TRUE; + g_dbus_method_invocation_return_value (context, NULL); } static gboolean set_ip_config_common (NMPPPManager *self, - GHashTable *hash, + GVariant *config_dict, const char *iface_prop, guint32 *out_mtu) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); - NMConnection *connection; + NMConnection *applied_connection; NMSettingPpp *s_ppp; - GValue *val; + const char *iface; - val = g_hash_table_lookup (hash, iface_prop); - if (!val || !G_VALUE_HOLDS_STRING (val)) { + if (!g_variant_lookup (config_dict, iface_prop, "&s", &iface)) { nm_log_err (LOGD_PPP, "no interface received!"); return FALSE; } if (priv->ip_iface == NULL) - priv->ip_iface = g_value_dup_string (val); + priv->ip_iface = g_strdup (iface); /* Got successful IP config; obviously the secrets worked */ - connection = nm_act_request_get_connection (priv->act_req); - g_assert (connection); - g_object_set_data (G_OBJECT (connection), PPP_MANAGER_SECRET_TRIES, NULL); + applied_connection = nm_act_request_get_applied_connection (priv->act_req); + g_object_set_data (G_OBJECT (applied_connection), PPP_MANAGER_SECRET_TRIES, NULL); - /* Get any custom MTU */ - s_ppp = nm_connection_get_setting_ppp (connection); - if (s_ppp && out_mtu) - *out_mtu = nm_setting_ppp_get_mtu (s_ppp); + if (out_mtu) { + /* Get any custom MTU */ + s_ppp = nm_connection_get_setting_ppp (applied_connection); + *out_mtu = s_ppp ? nm_setting_ppp_get_mtu (s_ppp) : 0; + } monitor_stats (self); return TRUE; } -static gboolean +static void impl_ppp_manager_set_ip4_config (NMPPPManager *manager, - GHashTable *config_hash, - GError **err) + GDBusMethodInvocation *context, + GVariant *config_dict) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); NMIP4Config *config; NMPlatformIP4Address address; - GValue *val; - int i; - guint32 mtu = 0; + guint32 u32; + GVariantIter *iter; nm_log_info (LOGD_PPP, "PPP manager (IPv4 Config Get) reply received."); remove_timeout_handler (manager); - config = nm_ip4_config_new (); + config = nm_ip4_config_new (nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface)); + memset (&address, 0, sizeof (address)); address.plen = 32; - val = (GValue *) g_hash_table_lookup (config_hash, NM_PPP_IP4_CONFIG_GATEWAY); - if (val) { - nm_ip4_config_set_gateway (config, g_value_get_uint (val)); - address.peer_address = g_value_get_uint (val); - } + if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_ADDRESS, "u", &u32)) + address.address = u32; - val = (GValue *) g_hash_table_lookup (config_hash, NM_PPP_IP4_CONFIG_ADDRESS); - if (val) - address.address = g_value_get_uint (val); + if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_GATEWAY, "u", &u32)) { + nm_ip4_config_set_gateway (config, u32); + address.peer_address = u32; + } else + address.peer_address = address.address; - val = (GValue *) g_hash_table_lookup (config_hash, NM_PPP_IP4_CONFIG_PREFIX); - if (val) - address.plen = g_value_get_uint (val); + if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_PREFIX, "u", &u32)) + address.plen = u32; if (address.address && address.plen) { address.source = NM_IP_CONFIG_SOURCE_PPP; @@ -573,55 +480,47 @@ impl_ppp_manager_set_ip4_config (NMPPPManager *manager, goto out; } - val = (GValue *) g_hash_table_lookup (config_hash, NM_PPP_IP4_CONFIG_DNS); - if (val) { - GArray *dns = (GArray *) g_value_get_boxed (val); - - for (i = 0; i < dns->len; i++) - nm_ip4_config_add_nameserver (config, g_array_index (dns, guint, i)); + if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_DNS, "au", &iter)) { + while (g_variant_iter_next (iter, "u", &u32)) + nm_ip4_config_add_nameserver (config, u32); + g_variant_iter_free (iter); } - val = (GValue *) g_hash_table_lookup (config_hash, NM_PPP_IP4_CONFIG_WINS); - if (val) { - GArray *wins = (GArray *) g_value_get_boxed (val); - - for (i = 0; i < wins->len; i++) - nm_ip4_config_add_wins (config, g_array_index (wins, guint, i)); + if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_WINS, "au", &iter)) { + while (g_variant_iter_next (iter, "u", &u32)) + nm_ip4_config_add_wins (config, u32); + g_variant_iter_free (iter); } - if (!set_ip_config_common (manager, config_hash, NM_PPP_IP4_CONFIG_INTERFACE, &mtu)) + if (!set_ip_config_common (manager, config_dict, NM_PPP_IP4_CONFIG_INTERFACE, &u32)) goto out; - if (mtu) - nm_ip4_config_set_mtu (config, mtu, NM_IP_CONFIG_SOURCE_PPP); + if (u32) + nm_ip4_config_set_mtu (config, u32, NM_IP_CONFIG_SOURCE_PPP); /* Push the IP4 config up to the device */ g_signal_emit (manager, signals[IP4_CONFIG], 0, priv->ip_iface, config); out: g_object_unref (config); - return TRUE; + g_dbus_method_invocation_return_value (context, NULL); } /* Converts the named Interface Identifier item to an IPv6 LL address and * returns the IID. */ static gboolean -iid_value_to_ll6_addr (GHashTable *hash, +iid_value_to_ll6_addr (GVariant *dict, const char *prop, struct in6_addr *out_addr, NMUtilsIPv6IfaceId *out_iid) { - GValue *val; guint64 iid; - val = g_hash_table_lookup (hash, prop); - if (!val || !G_VALUE_HOLDS (val, G_TYPE_UINT64)) { + if (!g_variant_lookup (dict, prop, "t", &iid)) { nm_log_dbg (LOGD_PPP, "pppd plugin property '%s' missing or not a uint64", prop); return FALSE; } - - iid = g_value_get_uint64 (val); g_return_val_if_fail (iid != 0, FALSE); /* Construct an IPv6 LL address from the interface identifier. See @@ -636,10 +535,10 @@ iid_value_to_ll6_addr (GHashTable *hash, return TRUE; } -static gboolean +static void impl_ppp_manager_set_ip6_config (NMPPPManager *manager, - GHashTable *hash, - GError **err) + GDBusMethodInvocation *context, + GVariant *config_dict) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager); NMIP6Config *config; @@ -651,20 +550,20 @@ impl_ppp_manager_set_ip6_config (NMPPPManager *manager, remove_timeout_handler (manager); - config = nm_ip6_config_new (); + config = nm_ip6_config_new (nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface)); memset (&addr, 0, sizeof (addr)); addr.plen = 64; - if (iid_value_to_ll6_addr (hash, NM_PPP_IP6_CONFIG_PEER_IID, &a, NULL)) { + if (iid_value_to_ll6_addr (config_dict, NM_PPP_IP6_CONFIG_PEER_IID, &a, NULL)) { nm_ip6_config_set_gateway (config, &a); addr.peer_address = a; } - if (iid_value_to_ll6_addr (hash, NM_PPP_IP6_CONFIG_OUR_IID, &addr.address, &iid)) { + if (iid_value_to_ll6_addr (config_dict, NM_PPP_IP6_CONFIG_OUR_IID, &addr.address, &iid)) { nm_ip6_config_add_address (config, &addr); - if (set_ip_config_common (manager, hash, NM_PPP_IP6_CONFIG_INTERFACE, NULL)) { + if (set_ip_config_common (manager, config_dict, NM_PPP_IP6_CONFIG_INTERFACE, NULL)) { /* Push the IPv6 config and interface identifier up to the device */ g_signal_emit (manager, signals[IP6_CONFIG], 0, priv->ip_iface, &iid, config); } @@ -672,7 +571,77 @@ impl_ppp_manager_set_ip6_config (NMPPPManager *manager, nm_log_err (LOGD_PPP, "invalid IPv6 address received!"); g_object_unref (config); - return TRUE; + g_dbus_method_invocation_return_value (context, NULL); +} + +static void +nm_ppp_manager_class_init (NMPPPManagerClass *manager_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (manager_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (manager_class); + + g_type_class_add_private (manager_class, sizeof (NMPPPManagerPrivate)); + + exported_object_class->export_path = NM_DBUS_PATH "/PPP"; + exported_object_class->export_on_construction = TRUE; + + object_class->dispose = dispose; + object_class->finalize = finalize; + object_class->get_property = get_property; + object_class->set_property = set_property; + + /* Properties */ + g_object_class_install_property + (object_class, PROP_PARENT_IFACE, + g_param_spec_string (NM_PPP_MANAGER_PARENT_IFACE, "", "", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + /* signals */ + signals[STATE_CHANGED] = + g_signal_new (NM_PPP_MANAGER_STATE_CHANGED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMPPPManagerClass, state_changed), + NULL, NULL, NULL, + G_TYPE_NONE, 1, + G_TYPE_UINT); + + signals[IP4_CONFIG] = + g_signal_new ("ip4-config", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMPPPManagerClass, ip4_config), + NULL, NULL, NULL, + G_TYPE_NONE, 2, + G_TYPE_STRING, + G_TYPE_OBJECT); + + signals[IP6_CONFIG] = + g_signal_new ("ip6-config", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMPPPManagerClass, ip6_config), + NULL, NULL, NULL, + G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_OBJECT); + + signals[STATS] = + g_signal_new ("stats", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMPPPManagerClass, stats), + NULL, NULL, NULL, + G_TYPE_NONE, 2, + G_TYPE_UINT, G_TYPE_UINT); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (manager_class), + NMDBUS_TYPE_PPP_MANAGER_SKELETON, + "NeedSecrets", impl_ppp_manager_need_secrets, + "SetIp4Config", impl_ppp_manager_set_ip4_config, + "SetIp6Config", impl_ppp_manager_set_ip6_config, + "SetState", impl_ppp_manager_set_state, + NULL); } /*******************************************/ @@ -828,6 +797,7 @@ ppp_watch_cb (GPid pid, gint status, gpointer user_data) nm_log_dbg (LOGD_PPP, "pppd pid %d cleaned up", priv->pid); priv->pid = 0; + priv->ppp_watch_id = 0; g_signal_emit (manager, signals[STATE_CHANGED], 0, NM_PPP_STATUS_DEAD); } @@ -854,7 +824,7 @@ create_pppd_cmd_line (NMPPPManager *self, GError **err) { NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (self); - const char *pppd_binary = NULL, *pppoe_binary = NULL; + const char *pppd_binary = NULL; NMCmdLine *cmd; gboolean ppp_debug; @@ -864,14 +834,6 @@ create_pppd_cmd_line (NMPPPManager *self, if (!pppd_binary) return NULL; - if ( pppoe - || ( adsl - && !strcmp (nm_setting_adsl_get_protocol (adsl), NM_SETTING_ADSL_PROTOCOL_PPPOE))) { - pppoe_binary = nm_utils_find_helper ("pppoe", NULL, err); - if (!pppoe_binary) - return NULL; - } - /* Create pppd command line */ cmd = nm_cmd_line_new (); nm_cmd_line_add_string (cmd, pppd_binary); @@ -899,30 +861,21 @@ create_pppd_cmd_line (NMPPPManager *self, } if (pppoe) { - GString *pppoe_arg; + char *dev_str; const char *pppoe_service; - char *quoted; - g_assert (pppoe_binary != NULL); - pppoe_arg = g_string_new (pppoe_binary); + nm_cmd_line_add_string (cmd, "plugin"); + nm_cmd_line_add_string (cmd, "rp-pppoe.so"); - g_string_append (pppoe_arg, " -I "); - quoted = g_shell_quote (priv->parent_iface); - g_string_append (pppoe_arg, quoted); - g_free (quoted); + dev_str = g_strdup_printf ("nic-%s", priv->parent_iface); + nm_cmd_line_add_string (cmd, dev_str); + g_free (dev_str); pppoe_service = nm_setting_pppoe_get_service (pppoe); if (pppoe_service) { - g_string_append (pppoe_arg, " -S "); - quoted = g_shell_quote (pppoe_service); - g_string_append (pppoe_arg, quoted); - g_free (quoted); + nm_cmd_line_add_string (cmd, "rp_pppoe_service"); + nm_cmd_line_add_string (cmd, pppoe_service); } - - nm_cmd_line_add_string (cmd, "pty"); - nm_cmd_line_add_string (cmd, pppoe_arg->str); - - g_string_free (pppoe_arg, TRUE); } else if (adsl) { const gchar *protocol = nm_setting_adsl_get_protocol (adsl); @@ -945,14 +898,9 @@ create_pppd_cmd_line (NMPPPManager *self, nm_cmd_line_add_string (cmd, "vc-encaps"); } else if (!strcmp (protocol, NM_SETTING_ADSL_PROTOCOL_PPPOE)) { - char *pppoe_arg; - - g_assert (pppoe_binary != NULL); - - pppoe_arg = g_strdup_printf ("%s -I %s", pppoe_binary, priv->parent_iface); - nm_cmd_line_add_string (cmd, "pty"); - nm_cmd_line_add_string (cmd, pppoe_arg); - g_free (pppoe_arg); + nm_cmd_line_add_string (cmd, "plugin"); + nm_cmd_line_add_string (cmd, "rp-pppoe.so"); + nm_cmd_line_add_string (cmd, priv->parent_iface); } nm_cmd_line_add_string (cmd, "noipdefault"); @@ -1022,7 +970,7 @@ create_pppd_cmd_line (NMPPPManager *self, nm_cmd_line_add_int (cmd, 0); nm_cmd_line_add_string (cmd, "ipparam"); - nm_cmd_line_add_string (cmd, priv->dbus_path); + nm_cmd_line_add_string (cmd, nm_exported_object_get_path (NM_EXPORTED_OBJECT (self))); nm_cmd_line_add_string (cmd, "plugin"); nm_cmd_line_add_string (cmd, NM_PPPD_PLUGIN); @@ -1094,7 +1042,7 @@ nm_ppp_manager_start (NMPPPManager *manager, if (stat ("/dev/ppp", &st) || !S_ISCHR (st.st_mode)) nm_utils_modprobe (NULL, FALSE, "ppp_generic", NULL); - connection = nm_act_request_get_connection (req); + connection = nm_act_request_get_applied_connection (req); g_assert (connection); s_ppp = nm_connection_get_setting_ppp (connection); @@ -1174,10 +1122,7 @@ _ppp_cleanup (NMPPPManager *manager) cancel_get_secrets (manager); - if (priv->monitor_id) { - g_source_remove (priv->monitor_id); - priv->monitor_id = 0; - } + nm_clear_g_source (&priv->monitor_id); if (priv->monitor_fd >= 0) { /* Get the stats one last time */ @@ -1186,15 +1131,8 @@ _ppp_cleanup (NMPPPManager *manager) priv->monitor_fd = -1; } - if (priv->ppp_timeout_handler) { - g_source_remove (priv->ppp_timeout_handler); - priv->ppp_timeout_handler = 0; - } - - if (priv->ppp_watch_id) { - g_source_remove (priv->ppp_watch_id); - priv->ppp_watch_id = 0; - } + nm_clear_g_source (&priv->ppp_timeout_handler); + nm_clear_g_source (&priv->ppp_watch_id); } /***********************************************************/ diff --git a/src/ppp-manager/nm-ppp-manager.h b/src/ppp-manager/nm-ppp-manager.h index f8cbda13..188be84e 100644 --- a/src/ppp-manager/nm-ppp-manager.h +++ b/src/ppp-manager/nm-ppp-manager.h @@ -22,10 +22,8 @@ #ifndef __NETWORKMANAGER_PPP_MANAGER_H__ #define __NETWORKMANAGER_PPP_MANAGER_H__ -#include -#include -#include +#include "nm-exported-object.h" #include "nm-ppp-status.h" #include "nm-activation-request.h" #include "nm-connection.h" @@ -43,12 +41,15 @@ #define NM_PPP_MANAGER_PARENT_IFACE "parent-iface" +/* signals */ +#define NM_PPP_MANAGER_STATE_CHANGED "state-changed" + typedef struct { - GObject parent; + NMExportedObject parent; } NMPPPManager; typedef struct { - GObjectClass parent; + NMExportedObjectClass parent; /* Signals */ void (*state_changed) (NMPPPManager *manager, NMPPPStatus status); diff --git a/src/ppp-manager/nm-pppd-plugin.c b/src/ppp-manager/nm-pppd-plugin.c index d5e8d707..1f1016ae 100644 --- a/src/ppp-manager/nm-pppd-plugin.c +++ b/src/ppp-manager/nm-pppd-plugin.c @@ -29,12 +29,12 @@ #include #include #include -#include #define INET6 #include #include +#include "nm-default.h" #include "nm-dbus-interface.h" #include "nm-pppd-plugin.h" #include "nm-ppp-status.h" @@ -372,9 +372,7 @@ plugin_init (void) GDBusConnection *bus; GError *err = NULL; -#if !GLIB_CHECK_VERSION (2, 35, 0) - g_type_init (); -#endif + nm_g_type_init (); g_message ("nm-ppp-plugin: (%s): initializing", __func__); diff --git a/src/ppp-manager/nm-pppd-plugin.h b/src/ppp-manager/nm-pppd-plugin.h index 2c3073e4..1a2ea09e 100644 --- a/src/ppp-manager/nm-pppd-plugin.h +++ b/src/ppp-manager/nm-pppd-plugin.h @@ -32,5 +32,3 @@ #define NM_PPP_IP6_CONFIG_OUR_IID "our-iid" #define NM_PPP_IP6_CONFIG_PEER_IID "peer-iid" -#define DBUS_TYPE_EUI64 (dbus_g_type_get_collection ("GByteArray", G_TYPE_UINT8)) - diff --git a/src/rdisc/Makefile.in b/src/rdisc/Makefile.in index 0df08e30..0ab39873 100644 --- a/src/rdisc/Makefile.in +++ b/src/rdisc/Makefile.in @@ -206,7 +206,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -218,8 +217,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -229,6 +226,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -283,16 +281,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -329,6 +324,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -357,7 +354,6 @@ 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@ @@ -372,6 +368,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -432,6 +430,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -439,6 +438,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ diff --git a/src/rdisc/nm-fake-rdisc.c b/src/rdisc/nm-fake-rdisc.c index 68f43c0e..001fd938 100644 --- a/src/rdisc/nm-fake-rdisc.c +++ b/src/rdisc/nm-fake-rdisc.c @@ -26,11 +26,9 @@ #include "nm-fake-rdisc.h" #include "nm-rdisc-private.h" -#include "nm-logging.h" +#include "nm-default.h" -#define debug(...) nm_log_dbg (LOGD_IP6, __VA_ARGS__) -#define warning(...) nm_log_warn (LOGD_IP6, __VA_ARGS__) -#define error(...) nm_log_err (LOGD_IP6, __VA_ARGS__) +#define _NMLOG_PREFIX_NAME "rdisc-fake" typedef struct { guint id; @@ -38,14 +36,23 @@ typedef struct { NMRDiscDHCPLevel dhcp_level; GArray *gateways; - GArray *addresses; - GArray *routes; + GArray *prefixes; GArray *dns_servers; GArray *dns_domains; int hop_limit; guint32 mtu; } FakeRa; +typedef struct { + struct in6_addr network; + int plen; + struct in6_addr gateway; + guint32 timestamp; + guint32 lifetime; + guint32 preferred; + NMRDiscPreference preference; +} FakePrefix; + typedef struct { guint receive_ra_id; GSList *ras; @@ -69,8 +76,7 @@ fake_ra_free (gpointer data) FakeRa *ra = data; g_array_free (ra->gateways, TRUE); - g_array_free (ra->addresses, TRUE); - g_array_free (ra->routes, TRUE); + g_array_free (ra->prefixes, TRUE); g_array_free (ra->dns_servers, TRUE); g_array_free (ra->dns_domains, TRUE); g_free (ra); @@ -112,8 +118,7 @@ nm_fake_rdisc_add_ra (NMFakeRDisc *self, ra->hop_limit = hop_limit; ra->mtu = mtu; ra->gateways = g_array_new (FALSE, FALSE, sizeof (NMRDiscGateway)); - ra->addresses = g_array_new (FALSE, FALSE, sizeof (NMRDiscAddress)); - ra->routes = g_array_new (FALSE, FALSE, sizeof (NMRDiscRoute)); + ra->prefixes = g_array_new (FALSE, FALSE, sizeof (FakePrefix)); ra->dns_servers = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSServer)); ra->dns_domains = g_array_new (FALSE, FALSE, sizeof (NMRDiscDNSDomain)); g_array_set_clear_func (ra->dns_domains, ra_dns_domain_free); @@ -144,49 +149,31 @@ nm_fake_rdisc_add_gateway (NMFakeRDisc *self, } void -nm_fake_rdisc_add_address (NMFakeRDisc *self, - guint ra_id, - const char *addr, - guint32 timestamp, - guint32 lifetime, - guint32 preferred) -{ - NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self); - FakeRa *ra = find_ra (priv->ras, ra_id); - NMRDiscAddress *a; - - g_assert (ra); - g_array_set_size (ra->addresses, ra->addresses->len + 1); - a = &g_array_index (ra->addresses, NMRDiscAddress, ra->addresses->len - 1); - g_assert (inet_pton (AF_INET6, addr, &a->address) == 1); - a->timestamp = timestamp; - a->lifetime = lifetime; - a->preferred = preferred; -} - -void -nm_fake_rdisc_add_route (NMFakeRDisc *self, - guint ra_id, - const char *network, - guint plen, - const char *gateway, - guint32 timestamp, - guint32 lifetime, - NMRDiscPreference preference) +nm_fake_rdisc_add_prefix (NMFakeRDisc *self, + guint ra_id, + const char *network, + guint plen, + const char *gateway, + guint32 timestamp, + guint32 lifetime, + guint32 preferred, + NMRDiscPreference preference) { NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (self); FakeRa *ra = find_ra (priv->ras, ra_id); - NMRDiscRoute *route; + FakePrefix *prefix; g_assert (ra); - g_array_set_size (ra->routes, ra->routes->len + 1); - route = &g_array_index (ra->routes, NMRDiscRoute, ra->routes->len - 1); - g_assert (inet_pton (AF_INET6, network, &route->network) == 1); - g_assert (inet_pton (AF_INET6, gateway, &route->gateway) == 1); - route->plen = plen; - route->timestamp = timestamp; - route->lifetime = lifetime; - route->preference = preference; + g_array_set_size (ra->prefixes, ra->prefixes->len + 1); + prefix = &g_array_index (ra->prefixes, FakePrefix, ra->prefixes->len - 1); + memset (prefix, 0, sizeof (*prefix)); + g_assert (inet_pton (AF_INET6, network, &prefix->network) == 1); + g_assert (inet_pton (AF_INET6, gateway, &prefix->gateway) == 1); + prefix->plen = plen; + prefix->timestamp = timestamp; + prefix->lifetime = lifetime; + prefix->preferred = preferred; + prefix->preference = preference; } void @@ -236,7 +223,7 @@ nm_fake_rdisc_done (NMFakeRDisc *self) /******************************************************************/ static gboolean -send_rs (NMRDisc *rdisc) +send_rs (NMRDisc *rdisc, GError **error) { g_signal_emit (rdisc, signals[RS_SENT], 0); return TRUE; @@ -267,18 +254,32 @@ receive_ra (gpointer user_data) changed |= NM_RDISC_CONFIG_GATEWAYS; } - for (i = 0; i < ra->addresses->len; i++) { - NMRDiscAddress *item = &g_array_index (ra->addresses, NMRDiscAddress, i); - - if (nm_rdisc_add_address (rdisc, item)) - changed |= NM_RDISC_CONFIG_ADDRESSES; - } - - for (i = 0; i < ra->routes->len; i++) { - NMRDiscRoute *item = &g_array_index (ra->routes, NMRDiscRoute, i); - - if (nm_rdisc_add_route (rdisc, item)) + for (i = 0; i < ra->prefixes->len; i++) { + FakePrefix *item = &g_array_index (ra->prefixes, FakePrefix, i); + NMRDiscRoute route = { + .network = item->network, + .plen = item->plen, + .gateway = item->gateway, + .timestamp = item->timestamp, + .lifetime = item->lifetime, + .preference = item->preference, + }; + + if (nm_rdisc_add_route (rdisc, &route)) changed |= NM_RDISC_CONFIG_ROUTES; + + if (item->plen == 64) { + NMRDiscAddress address = { + .address = item->network, + .timestamp = item->timestamp, + .lifetime = item->lifetime, + .preferred = item->preferred, + .dad_counter = 0, + }; + + if (nm_rdisc_complete_and_add_address (rdisc, &address)) + changed |= NM_RDISC_CONFIG_ADDRESSES; + } } for (i = 0; i < ra->dns_servers->len; i++) { @@ -366,10 +367,7 @@ dispose (GObject *object) { NMFakeRDiscPrivate *priv = NM_FAKE_RDISC_GET_PRIVATE (object); - if (priv->receive_ra_id) { - g_source_remove (priv->receive_ra_id); - priv->receive_ra_id = 0; - } + nm_clear_g_source (&priv->receive_ra_id); g_slist_free_full (priv->ras, fake_ra_free); priv->ras = NULL; diff --git a/src/rdisc/nm-fake-rdisc.h b/src/rdisc/nm-fake-rdisc.h index 74f74897..1082ba5e 100644 --- a/src/rdisc/nm-fake-rdisc.h +++ b/src/rdisc/nm-fake-rdisc.h @@ -59,20 +59,14 @@ void nm_fake_rdisc_add_gateway (NMFakeRDisc *self, guint32 lifetime, NMRDiscPreference preference); -void nm_fake_rdisc_add_address (NMFakeRDisc *self, - guint ra_id, - const char *addr, - guint32 timestamp, - guint32 lifetime, - guint32 preferred); - -void nm_fake_rdisc_add_route (NMFakeRDisc *self, +void nm_fake_rdisc_add_prefix (NMFakeRDisc *self, guint ra_id, const char *network, guint plen, const char *gateway, guint32 timestamp, guint32 lifetime, + guint32 preferred, NMRDiscPreference preference); void nm_fake_rdisc_add_dns_server (NMFakeRDisc *self, diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c index 46f81476..46000994 100644 --- a/src/rdisc/nm-lndp-rdisc.c +++ b/src/rdisc/nm-lndp-rdisc.c @@ -30,12 +30,10 @@ #include "nm-rdisc-private.h" #include "NetworkManagerUtils.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-platform.h" -#define debug(...) nm_log_dbg (LOGD_IP6, __VA_ARGS__) -#define warning(...) nm_log_warn (LOGD_IP6, __VA_ARGS__) -#define error(...) nm_log_err (LOGD_IP6, __VA_ARGS__) +#define _NMLOG_PREFIX_NAME "rdisc-lndp" typedef struct { struct ndp *ndp; @@ -52,20 +50,28 @@ G_DEFINE_TYPE (NMLNDPRDisc, nm_lndp_rdisc, NM_TYPE_RDISC) /******************************************************************/ static gboolean -send_rs (NMRDisc *rdisc) +send_rs (NMRDisc *rdisc, GError **error) { NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); struct ndp_msg *msg; - int error; + int errsv; - error = ndp_msg_new (&msg, NDP_MSG_RS); - g_assert (!error); + errsv = ndp_msg_new (&msg, NDP_MSG_RS); + if (errsv) { + errsv = errsv > 0 ? errsv : -errsv; + g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "cannot create router solicitation"); + return FALSE; + } ndp_msg_ifindex_set (msg, rdisc->ifindex); - error = ndp_msg_send (priv->ndp, msg); + errsv = ndp_msg_send (priv->ndp, msg); ndp_msg_destroy (msg); - if (error) { - error ("(%s): cannot send router solicitation: %d.", rdisc->ifname, error); + if (errsv) { + errsv = errsv > 0 ? errsv : -errsv; + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "%s (%d)", + g_strerror (errsv), errsv); return FALSE; } @@ -109,7 +115,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) * single time when the configuration is finished and updates can * come at any time. */ - debug ("(%s): received router advertisement at %u", rdisc->ifname, now); + _LOGD ("received router advertisement at %u", now); /* DHCP level: * @@ -165,7 +171,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) /* Address */ if (ndp_msg_opt_prefix_flag_auto_addr_conf (msg, offset)) { - if (route.plen == 64 && rdisc->iid.id) { + if (route.plen == 64) { memset (&address, 0, sizeof (address)); address.address = route.network; address.timestamp = now; @@ -174,10 +180,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) if (address.preferred > address.lifetime) address.preferred = address.lifetime; - /* Add the Interface Identifier to the lower 64 bits */ - nm_utils_ipv6_addr_set_interface_identfier (&address.address, rdisc->iid); - - if (nm_rdisc_add_address (rdisc, &address)) + if (nm_rdisc_complete_and_add_address (rdisc, &address)) changed |= NM_RDISC_CONFIG_ADDRESSES; } } @@ -260,7 +263,7 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data) * Kernel would set it, but would flush out all IPv6 addresses away * from the link, even the link-local, and we wouldn't be able to * listen for further RAs that could fix the MTU. */ - warning ("(%s): MTU too small for IPv6 ignored: %d", rdisc->ifname, mtu); + _LOGW ("MTU too small for IPv6 ignored: %d", mtu); } } @@ -273,7 +276,7 @@ event_ready (GIOChannel *source, GIOCondition condition, NMRDisc *rdisc) { NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); - debug ("(%s): processing libndp events.", rdisc->ifname); + _LOGD ("processing libndp events"); ndp_callall_eventfd_handler (priv->ndp); return G_SOURCE_CONTINUE; } @@ -302,16 +305,24 @@ ipv6_sysctl_get (const char *ifname, const char *property, gint32 defval) } NMRDisc * -nm_lndp_rdisc_new (int ifindex, const char *ifname) +nm_lndp_rdisc_new (int ifindex, + const char *ifname, + const char *uuid, + NMSettingIP6ConfigAddrGenMode addr_gen_mode, + GError **error) { NMRDisc *rdisc; NMLNDPRDiscPrivate *priv; - int error; + int errsv; + + g_return_val_if_fail (!error || !*error, NULL); rdisc = g_object_new (NM_TYPE_LNDP_RDISC, NULL); rdisc->ifindex = ifindex; rdisc->ifname = g_strdup (ifname); + rdisc->uuid = g_strdup (uuid); + rdisc->addr_gen_mode = addr_gen_mode; rdisc->max_addresses = ipv6_sysctl_get (ifname, "max_addresses", NM_RDISC_MAX_ADDRESSES_DEFAULT); @@ -321,10 +332,13 @@ nm_lndp_rdisc_new (int ifindex, const char *ifname) NM_RDISC_RTR_SOLICITATION_INTERVAL_DEFAULT); priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); - error = ndp_open (&priv->ndp); - if (error != 0) { + errsv = ndp_open (&priv->ndp); + if (errsv != 0) { + errsv = errsv > 0 ? errsv : -errsv; + g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, + "failure creating libndp socket: %s (%d)", + g_strerror (errsv), errsv); g_object_unref (rdisc); - debug ("(%s): error creating socket for NDP; errno=%d", ifname, -error); return NULL; } return rdisc; @@ -341,10 +355,7 @@ dispose (GObject *object) NMLNDPRDisc *rdisc = NM_LNDP_RDISC (object); NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc); - if (priv->event_id) { - g_source_remove (priv->event_id); - priv->event_id = 0; - } + nm_clear_g_source (&priv->event_id); g_clear_pointer (&priv->event_channel, g_io_channel_unref); if (priv->ndp) { diff --git a/src/rdisc/nm-lndp-rdisc.h b/src/rdisc/nm-lndp-rdisc.h index 407e1f92..e6706e3c 100644 --- a/src/rdisc/nm-lndp-rdisc.h +++ b/src/rdisc/nm-lndp-rdisc.h @@ -44,6 +44,10 @@ typedef struct { GType nm_lndp_rdisc_get_type (void); -NMRDisc *nm_lndp_rdisc_new (int ifindex, const char *ifname); +NMRDisc *nm_lndp_rdisc_new (int ifindex, + const char *ifname, + const char *uuid, + NMSettingIP6ConfigAddrGenMode addr_gen_mode, + GError **error); #endif /* __NETWORKMANAGER_LNDP_RDISC_H__ */ diff --git a/src/rdisc/nm-rdisc-private.h b/src/rdisc/nm-rdisc-private.h index f95949de..c0ec739a 100644 --- a/src/rdisc/nm-rdisc-private.h +++ b/src/rdisc/nm-rdisc-private.h @@ -27,10 +27,39 @@ void nm_rdisc_ra_received (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed); -gboolean nm_rdisc_add_gateway (NMRDisc *rdisc, const NMRDiscGateway *new); -gboolean nm_rdisc_add_address (NMRDisc *rdisc, const NMRDiscAddress *new); -gboolean nm_rdisc_add_route (NMRDisc *rdisc, const NMRDiscRoute *new); -gboolean nm_rdisc_add_dns_server (NMRDisc *rdisc, const NMRDiscDNSServer *new); -gboolean nm_rdisc_add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new); +gboolean nm_rdisc_add_gateway (NMRDisc *rdisc, const NMRDiscGateway *new); +gboolean nm_rdisc_complete_and_add_address (NMRDisc *rdisc, NMRDiscAddress *new); +gboolean nm_rdisc_add_route (NMRDisc *rdisc, const NMRDiscRoute *new); +gboolean nm_rdisc_add_dns_server (NMRDisc *rdisc, const NMRDiscDNSServer *new); +gboolean nm_rdisc_add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new); + +/*********************************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_IP6 +#define _NMLOG(level, ...) _LOG(level, _NMLOG_DOMAIN, rdisc, __VA_ARGS__) + +#define _LOG(level, domain, self, ...) \ + G_STMT_START { \ + const NMLogLevel __level = (level); \ + const NMLogDomain __domain = (domain); \ + \ + if (nm_logging_enabled (__level, __domain)) { \ + char __prefix[64]; \ + const char *__p_prefix = _NMLOG_PREFIX_NAME; \ + const NMRDisc *const __self = (self); \ + \ + if (__self) { \ + g_snprintf (__prefix, sizeof (__prefix), "%s[%p,%s%s%s]", \ + _NMLOG_PREFIX_NAME, __self, \ + NM_PRINT_FMT_QUOTE_STRING (__self->ifname)); \ + __p_prefix = __prefix; \ + } \ + _nm_log (__level, __domain, 0, \ + "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + __p_prefix _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } \ + } G_STMT_END + +/*********************************************************************************************/ #endif /* __NETWORKMANAGER_RDISC_PRIVATE_H__ */ diff --git a/src/rdisc/nm-rdisc.c b/src/rdisc/nm-rdisc.c index a73ab7d0..6133ae28 100644 --- a/src/rdisc/nm-rdisc.c +++ b/src/rdisc/nm-rdisc.c @@ -27,10 +27,12 @@ #include "nm-rdisc.h" #include "nm-rdisc-private.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-utils.h" -#define debug(...) nm_log_dbg (LOGD_IP6, __VA_ARGS__) +#include + +#define _NMLOG_PREFIX_NAME "rdisc" typedef struct { int solicitations_left; @@ -38,6 +40,7 @@ typedef struct { gint64 last_rs; guint ra_timeout_id; /* first RA timeout */ guint timeout_id; /* prefix/dns/etc lifetime timeout */ + char *last_send_rs_error; } NMRDiscPrivate; #define NM_RDISC_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_RDISC, NMRDiscPrivate)) @@ -87,11 +90,63 @@ nm_rdisc_add_gateway (NMRDisc *rdisc, const NMRDiscGateway *new) return !!new->lifetime; } +/** + * complete_address: + * @rdisc: the #NMRDisc + * @addr: the #NMRDiscAddress + * + * Adds the host part to the address that has network part set. + * If the address already has a host part, add a different host part + * if possible (this is useful in case DAD failed). + * + * Can fail if a different address can not be generated (DAD failure + * for an EUI-64 address or DAD counter overflow). + * + * Returns: %TRUE if the address could be completed, %FALSE otherwise. + **/ +static gboolean +complete_address (NMRDisc *rdisc, NMRDiscAddress *addr) +{ + GError *error = NULL; + + if (rdisc->addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) { + if (!nm_utils_ipv6_addr_set_stable_privacy (&addr->address, + rdisc->ifname, + rdisc->uuid, + addr->dad_counter++, + &error)) { + _LOGW ("complete-address: failed to generate an stable-privacy address: %s", + error->message); + g_clear_error (&error); + return FALSE; + } + _LOGD ("complete-address: using an stable-privacy address"); + return TRUE; + } + + if (!rdisc->iid.id) { + _LOGW ("complete-address: can't generate an EUI-64 address: no interface identifier"); + return FALSE; + } + + if (addr->address.s6_addr32[2] == 0x0 && addr->address.s6_addr32[3] == 0x0) { + _LOGD ("complete-address: adding an EUI-64 address"); + nm_utils_ipv6_addr_set_interface_identfier (&addr->address, rdisc->iid); + return TRUE; + } + + _LOGW ("complete-address: can't generate a new EUI-64 address"); + return FALSE; +} + gboolean -nm_rdisc_add_address (NMRDisc *rdisc, const NMRDiscAddress *new) +nm_rdisc_complete_and_add_address (NMRDisc *rdisc, NMRDiscAddress *new) { int i; + if (!complete_address (rdisc, new)) + return FALSE; + for (i = 0; i < rdisc->addresses->len; i++) { NMRDiscAddress *item = &g_array_index (rdisc->addresses, NMRDiscAddress, i); @@ -219,28 +274,6 @@ nm_rdisc_add_dns_domain (NMRDisc *rdisc, const NMRDiscDNSDomain *new) /******************************************************************/ -static void -clear_ra_timeout (NMRDisc *rdisc) -{ - NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); - - if (priv->ra_timeout_id) { - g_source_remove (priv->ra_timeout_id); - priv->ra_timeout_id = 0; - } -} - -static void -clear_rs_timeout (NMRDisc *rdisc) -{ - NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); - - if (priv->send_rs_id) { - g_source_remove (priv->send_rs_id); - priv->send_rs_id = 0; - } -} - /** * nm_rdisc_set_iid: * @rdisc: the #NMRDisc @@ -255,7 +288,10 @@ clear_rs_timeout (NMRDisc *rdisc) * the old identifier are removed. The caller should ensure the addresses * will be reset by soliciting router advertisements. * - * Returns: %TRUE if the token was changed, %FALSE otherwise. + * In case the stable privacy addressing is used %FALSE is returned and + * addresses are left untouched. + * + * Returns: %TRUE if addresses need to be regenerated, %FALSE otherwise. **/ gboolean nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid) @@ -264,8 +300,12 @@ nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid) if (rdisc->iid.id != iid.id) { rdisc->iid = iid; + + if (rdisc->addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY) + return FALSE; + if (rdisc->addresses->len) { - debug ("(%s) IPv6 interface identifier changed, flushing addresses", rdisc->ifname); + _LOGD ("IPv6 interface identifier changed, flushing addresses"); g_array_remove_range (rdisc->addresses, 0, rdisc->addresses->len); g_signal_emit_by_name (rdisc, NM_RDISC_CONFIG_CHANGED, NM_RDISC_CONFIG_ADDRESSES); } @@ -280,21 +320,34 @@ send_rs (NMRDisc *rdisc) { NMRDiscClass *klass = NM_RDISC_GET_CLASS (rdisc); NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); + GError *error = NULL; - debug ("(%s): sending router solicitation", rdisc->ifname); - - if (klass->send_rs (rdisc)) + if (klass->send_rs (rdisc, &error)) { + _LOGD ("router solicitation sent"); priv->solicitations_left--; + g_clear_pointer (&priv->last_send_rs_error, g_free); + } else { + gboolean different_message; + + different_message = g_strcmp0 (priv->last_send_rs_error, error->message) != 0; + _NMLOG (different_message ? LOGL_WARN : LOGL_DEBUG, + "failure sending router solicitation: %s", error->message); + if (different_message) { + g_clear_pointer (&priv->last_send_rs_error, g_free); + priv->last_send_rs_error = g_strdup (error->message); + } + g_clear_error (&error); + } priv->last_rs = nm_utils_get_monotonic_timestamp_s (); if (priv->solicitations_left > 0) { - debug ("(%s): scheduling router solicitation retry in %d seconds.", - rdisc->ifname, rdisc->rtr_solicitation_interval); + _LOGD ("scheduling router solicitation retry in %d seconds.", + rdisc->rtr_solicitation_interval); priv->send_rs_id = g_timeout_add_seconds (rdisc->rtr_solicitation_interval, (GSourceFunc) send_rs, rdisc); } else { - debug ("(%s): did not receive a router advertisement after %d solicitations.", - rdisc->ifname, rdisc->rtr_solicitations); + _LOGD ("did not receive a router advertisement after %d solicitations.", + rdisc->rtr_solicitations); priv->send_rs_id = 0; } @@ -312,8 +365,8 @@ solicit (NMRDisc *rdisc) priv->solicitations_left = rdisc->rtr_solicitations; next = CLAMP (priv->last_rs + rdisc->rtr_solicitation_interval - now, 0, G_MAXINT32); - debug ("(%s): scheduling explicit router solicitation request in %" G_GINT64_FORMAT " seconds.", - rdisc->ifname, next); + _LOGD ("scheduling explicit router solicitation request in %" G_GINT64_FORMAT " seconds.", + next); priv->send_rs_id = g_timeout_add_seconds ((guint32) next, (GSourceFunc) send_rs, rdisc); } } @@ -337,12 +390,12 @@ nm_rdisc_start (NMRDisc *rdisc) g_assert (klass->start); - debug ("(%s): starting router discovery: %d", rdisc->ifname, rdisc->ifindex); + _LOGD ("starting router discovery: %d", rdisc->ifindex); - clear_ra_timeout (rdisc); + nm_clear_g_source (&priv->ra_timeout_id); ra_wait_secs = CLAMP (rdisc->rtr_solicitations * rdisc->rtr_solicitation_interval, 30, 120); priv->ra_timeout_id = g_timeout_add_seconds (ra_wait_secs, rdisc_ra_timeout_cb, rdisc); - debug ("(%s): scheduling RA timeout in %d seconds", rdisc->ifname, ra_wait_secs); + _LOGD ("scheduling RA timeout in %d seconds", ra_wait_secs); if (klass->start) klass->start (rdisc); @@ -350,6 +403,28 @@ nm_rdisc_start (NMRDisc *rdisc) solicit (rdisc); } +void +nm_rdisc_dad_failed (NMRDisc *rdisc, struct in6_addr *address) +{ + int i; + gboolean changed = FALSE; + + for (i = 0; i < rdisc->addresses->len; i++) { + NMRDiscAddress *item = &g_array_index (rdisc->addresses, NMRDiscAddress, i); + + if (!IN6_ARE_ADDR_EQUAL (&item->address, address)) + continue; + + _LOGD ("DAD failed for discovered address %s", nm_utils_inet6_ntop (address, NULL)); + if (!complete_address (rdisc, item)) + g_array_remove_index (rdisc->addresses, i--); + changed = TRUE; + } + + if (changed) + g_signal_emit_by_name (rdisc, NM_RDISC_CONFIG_CHANGED, NM_RDISC_CONFIG_ADDRESSES); +} + #define CONFIG_MAP_MAX_STR 7 static void @@ -394,27 +469,27 @@ config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed) char changedstr[CONFIG_MAP_MAX_STR]; char addrstr[INET6_ADDRSTRLEN]; - if (nm_logging_enabled (LOGL_DEBUG, LOGD_IP6)) { + if (_LOGD_ENABLED ()) { config_map_to_string (changed, changedstr); - debug ("(%s): router discovery configuration changed [%s]:", rdisc->ifname, changedstr); - debug (" dhcp-level %s", dhcp_level_to_string (rdisc->dhcp_level)); + _LOGD ("router discovery configuration changed [%s]:", changedstr); + _LOGD (" dhcp-level %s", dhcp_level_to_string (rdisc->dhcp_level)); for (i = 0; i < rdisc->gateways->len; i++) { NMRDiscGateway *gateway = &g_array_index (rdisc->gateways, NMRDiscGateway, i); inet_ntop (AF_INET6, &gateway->address, addrstr, sizeof (addrstr)); - debug (" gateway %s pref %d exp %u", addrstr, gateway->preference, expiry (gateway)); + _LOGD (" gateway %s pref %d exp %u", addrstr, gateway->preference, expiry (gateway)); } for (i = 0; i < rdisc->addresses->len; i++) { NMRDiscAddress *address = &g_array_index (rdisc->addresses, NMRDiscAddress, i); inet_ntop (AF_INET6, &address->address, addrstr, sizeof (addrstr)); - debug (" address %s exp %u", addrstr, expiry (address)); + _LOGD (" address %s exp %u", addrstr, expiry (address)); } for (i = 0; i < rdisc->routes->len; i++) { NMRDiscRoute *route = &g_array_index (rdisc->routes, NMRDiscRoute, i); inet_ntop (AF_INET6, &route->network, addrstr, sizeof (addrstr)); - debug (" route %s/%d via %s pref %d exp %u", addrstr, route->plen, + _LOGD (" route %s/%d via %s pref %d exp %u", addrstr, route->plen, nm_utils_inet6_ntop (&route->gateway, NULL), route->preference, expiry (route)); } @@ -422,12 +497,12 @@ config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed) NMRDiscDNSServer *dns_server = &g_array_index (rdisc->dns_servers, NMRDiscDNSServer, i); inet_ntop (AF_INET6, &dns_server->address, addrstr, sizeof (addrstr)); - debug (" dns_server %s exp %u", addrstr, expiry (dns_server)); + _LOGD (" dns_server %s exp %u", addrstr, expiry (dns_server)); } for (i = 0; i < rdisc->dns_domains->len; i++) { NMRDiscDNSDomain *dns_domain = &g_array_index (rdisc->dns_domains, NMRDiscDNSDomain, i); - debug (" dns_domain %s exp %u", dns_domain->domain, expiry (dns_domain)); + _LOGD (" dns_domain %s exp %u", dns_domain->domain, expiry (dns_domain)); } } } @@ -548,10 +623,7 @@ check_timestamps (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed) guint32 never = G_MAXINT32; guint32 nextevent = never; - if (priv->timeout_id) { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } + nm_clear_g_source (&priv->timeout_id); clean_gateways (rdisc, now, &changed, &nextevent); clean_addresses (rdisc, now, &changed, &nextevent); @@ -564,8 +636,8 @@ check_timestamps (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed) if (nextevent != never) { g_return_if_fail (nextevent > now); - debug ("(%s): scheduling next now/lifetime check: %u seconds", - rdisc->ifname, nextevent - now); + _LOGD ("scheduling next now/lifetime check: %u seconds", + nextevent - now); priv->timeout_id = g_timeout_add_seconds (nextevent - now, timeout_cb, rdisc); } } @@ -581,8 +653,11 @@ timeout_cb (gpointer user_data) void nm_rdisc_ra_received (NMRDisc *rdisc, guint32 now, NMRDiscConfigMap changed) { - clear_ra_timeout (rdisc); - clear_rs_timeout (rdisc); + NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); + + nm_clear_g_source (&priv->ra_timeout_id); + nm_clear_g_source (&priv->send_rs_id); + g_clear_pointer (&priv->last_send_rs_error, g_free); check_timestamps (rdisc, now, changed); } @@ -619,13 +694,11 @@ dispose (GObject *object) NMRDisc *rdisc = NM_RDISC (object); NMRDiscPrivate *priv = NM_RDISC_GET_PRIVATE (rdisc); - clear_ra_timeout (rdisc); - clear_rs_timeout (rdisc); + nm_clear_g_source (&priv->ra_timeout_id); + nm_clear_g_source (&priv->send_rs_id); + g_clear_pointer (&priv->last_send_rs_error, g_free); - if (priv->timeout_id) { - g_source_remove (priv->timeout_id); - priv->timeout_id = 0; - } + nm_clear_g_source (&priv->timeout_id); G_OBJECT_CLASS (nm_rdisc_parent_class)->dispose (object); } @@ -636,6 +709,7 @@ finalize (GObject *object) NMRDisc *rdisc = NM_RDISC (object); g_free (rdisc->ifname); + g_free (rdisc->uuid); g_array_unref (rdisc->gateways); g_array_unref (rdisc->addresses); g_array_unref (rdisc->routes); diff --git a/src/rdisc/nm-rdisc.h b/src/rdisc/nm-rdisc.h index 463e1912..51e2602f 100644 --- a/src/rdisc/nm-rdisc.h +++ b/src/rdisc/nm-rdisc.h @@ -21,11 +21,12 @@ #ifndef __NETWORKMANAGER_RDISC_H__ #define __NETWORKMANAGER_RDISC_H__ -#include #include #include +#include "nm-default.h" +#include "nm-setting-ip6-config.h" #include "NetworkManagerUtils.h" #define NM_TYPE_RDISC (nm_rdisc_get_type ()) @@ -61,6 +62,7 @@ typedef struct { typedef struct { struct in6_addr address; + guint8 dad_counter; guint32 timestamp; guint32 lifetime; guint32 preferred; @@ -114,6 +116,8 @@ typedef struct { int ifindex; char *ifname; + char *uuid; + NMSettingIP6ConfigAddrGenMode addr_gen_mode; NMUtilsIPv6IfaceId iid; gint32 max_addresses; gint32 rtr_solicitations; @@ -133,7 +137,7 @@ typedef struct { GObjectClass parent; void (*start) (NMRDisc *rdisc); - gboolean (*send_rs) (NMRDisc *rdisc); + gboolean (*send_rs) (NMRDisc *rdisc, GError **error); void (*config_changed) (NMRDisc *rdisc, NMRDiscConfigMap changed); void (*ra_process) (NMRDisc *rdisc); void (*ra_timeout) (NMRDisc *rdisc); @@ -143,5 +147,6 @@ GType nm_rdisc_get_type (void); gboolean nm_rdisc_set_iid (NMRDisc *rdisc, const NMUtilsIPv6IfaceId iid); void nm_rdisc_start (NMRDisc *rdisc); +void nm_rdisc_dad_failed (NMRDisc *rdisc, struct in6_addr *address); #endif /* __NETWORKMANAGER_RDISC_H__ */ diff --git a/src/rdisc/tests/Makefile.am b/src/rdisc/tests/Makefile.am index 995f68bd..d520e416 100644 --- a/src/rdisc/tests/Makefile.am +++ b/src/rdisc/tests/Makefile.am @@ -1,14 +1,14 @@ AM_CPPFLAGS = \ -I${top_srcdir} \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I${top_srcdir}/src \ -I${top_srcdir}/src/platform \ -I${top_srcdir}/libnm-core \ -I${top_builddir}/libnm-core \ -I${srcdir}/.. \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ $(LIBNDP_CFLAGS) @@ -16,7 +16,6 @@ AM_CPPFLAGS = \ AM_CFLAGS = $(CODE_COVERAGE_CFLAGS) AM_LDFLAGS = \ $(GLIB_LIBS) \ - $(DBUS_LIBS) \ $(CODE_COVERAGE_LDFLAGS) @GNOME_CODE_COVERAGE_RULES@ diff --git a/src/rdisc/tests/Makefile.in b/src/rdisc/tests/Makefile.in index 1a5c70e2..91b12677 100644 --- a/src/rdisc/tests/Makefile.in +++ b/src/rdisc/tests/Makefile.in @@ -407,7 +407,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -419,8 +418,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -430,6 +427,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -484,16 +482,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -530,6 +525,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -558,7 +555,6 @@ 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@ @@ -573,6 +569,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -633,6 +631,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -640,6 +639,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -657,15 +657,15 @@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ AM_CPPFLAGS = \ -I${top_srcdir} \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I${top_srcdir}/src \ -I${top_srcdir}/src/platform \ -I${top_srcdir}/libnm-core \ -I${top_builddir}/libnm-core \ -I${srcdir}/.. \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ $(LIBNDP_CFLAGS) @@ -673,7 +673,6 @@ AM_CPPFLAGS = \ AM_CFLAGS = $(CODE_COVERAGE_CFLAGS) AM_LDFLAGS = \ $(GLIB_LIBS) \ - $(DBUS_LIBS) \ $(CODE_COVERAGE_LDFLAGS) test_rdisc_linux_SOURCES = \ diff --git a/src/rdisc/tests/test-rdisc-fake.c b/src/rdisc/tests/test-rdisc-fake.c index 33672637..ad045cff 100644 --- a/src/rdisc/tests/test-rdisc-fake.c +++ b/src/rdisc/tests/test-rdisc-fake.c @@ -25,7 +25,7 @@ #include "nm-rdisc.h" #include "nm-fake-rdisc.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-fake-platform.h" @@ -37,8 +37,11 @@ rdisc_new (void) NMRDisc *rdisc; const int ifindex = 1; const char *ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex); + NMUtilsIPv6IfaceId iid = { }; rdisc = nm_fake_rdisc_new (ifindex, ifname); + iid.id_u8[7] = 1; + nm_rdisc_set_iid (rdisc, iid); g_assert (rdisc); return NM_FAKE_RDISC (rdisc); } @@ -145,8 +148,7 @@ test_simple (void) id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_OTHERCONF, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 10, NM_RDISC_PREFERENCE_MEDIUM); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10); - nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10); + nm_fake_rdisc_add_prefix (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 10); nm_fake_rdisc_add_dns_server (rdisc, id, "2001:db8:c:c::1", now, 10); nm_fake_rdisc_add_dns_domain (rdisc, id, "foobar.com", now, 10); @@ -198,7 +200,7 @@ test_everything_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, TestData *dat g_assert_cmpint (rdisc->gateways->len, ==, 1); match_gateway (rdisc->gateways, 0, "fe80::2", data->timestamp1, 10, NM_RDISC_PREFERENCE_MEDIUM); g_assert_cmpint (rdisc->addresses->len, ==, 1); - match_address (rdisc->addresses, 0, "2001:db8:a:a::2", data->timestamp1, 10, 10); + match_address (rdisc->addresses, 0, "2001:db8:a:b::1", data->timestamp1, 10, 10); g_assert_cmpint (rdisc->routes->len, ==, 1); match_route (rdisc->routes, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1, 10, 10); g_assert_cmpint (rdisc->dns_servers->len, ==, 1); @@ -225,8 +227,7 @@ test_everything (void) id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 10, NM_RDISC_PREFERENCE_MEDIUM); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10); - nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10); + nm_fake_rdisc_add_prefix (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 10); nm_fake_rdisc_add_dns_server (rdisc, id, "2001:db8:c:c::1", now, 10); nm_fake_rdisc_add_dns_domain (rdisc, id, "foobar.com", now, 10); @@ -234,15 +235,13 @@ test_everything (void) id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 0, NM_RDISC_PREFERENCE_MEDIUM); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 0, 0); - nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 0, 0); + nm_fake_rdisc_add_prefix (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 0, 0, 0); nm_fake_rdisc_add_dns_server (rdisc, id, "2001:db8:c:c::1", now, 0); nm_fake_rdisc_add_dns_domain (rdisc, id, "foobar.com", now, 0); /* and add some new stuff */ nm_fake_rdisc_add_gateway (rdisc, id, "fe80::2", now, 10, NM_RDISC_PREFERENCE_MEDIUM); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::2", now, 10, 10); - nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:b::", 64, "fe80::2", now, 10, 10); + nm_fake_rdisc_add_prefix (rdisc, id, "2001:db8:a:b::", 64, "fe80::2", now, 10, 10, 10); nm_fake_rdisc_add_dns_server (rdisc, id, "2001:db8:c:c::2", now, 10); nm_fake_rdisc_add_dns_domain (rdisc, id, "foobar2.com", now, 10); @@ -276,7 +275,7 @@ test_preference_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, TestData *dat match_gateway (rdisc->gateways, 1, "fe80::1", data->timestamp1, 10, NM_RDISC_PREFERENCE_LOW); g_assert_cmpint (rdisc->addresses->len, ==, 2); match_address (rdisc->addresses, 0, "2001:db8:a:a::1", data->timestamp1, 10, 10); - match_address (rdisc->addresses, 1, "2001:db8:a:a::2", data->timestamp1 + 1, 10, 10); + match_address (rdisc->addresses, 1, "2001:db8:a:b::1", data->timestamp1 + 1, 10, 10); g_assert_cmpint (rdisc->routes->len, ==, 2); match_route (rdisc->routes, 0, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1 + 1, 10, 10); match_route (rdisc->routes, 1, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1, 10, 5); @@ -290,7 +289,7 @@ test_preference_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, TestData *dat match_gateway (rdisc->gateways, 1, "fe80::2", data->timestamp1 + 1, 10, NM_RDISC_PREFERENCE_MEDIUM); g_assert_cmpint (rdisc->addresses->len, ==, 2); match_address (rdisc->addresses, 0, "2001:db8:a:a::1", data->timestamp1 + 2, 10, 10); - match_address (rdisc->addresses, 1, "2001:db8:a:a::2", data->timestamp1 + 1, 10, 10); + match_address (rdisc->addresses, 1, "2001:db8:a:b::1", data->timestamp1 + 1, 10, 10); g_assert_cmpint (rdisc->routes->len, ==, 2); match_route (rdisc->routes, 0, "2001:db8:a:a::", 64, "fe80::1", data->timestamp1 + 2, 10, 15); match_route (rdisc->routes, 1, "2001:db8:a:b::", 64, "fe80::2", data->timestamp1 + 1, 10, 10); @@ -318,20 +317,17 @@ test_preference (void) id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 10, NM_RDISC_PREFERENCE_LOW); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10); - nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 5); + nm_fake_rdisc_add_prefix (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 5); id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::2", ++now, 10, NM_RDISC_PREFERENCE_MEDIUM); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::2", now, 10, 10); - nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:b::", 64, "fe80::2", now, 10, 10); + nm_fake_rdisc_add_prefix (rdisc, id, "2001:db8:a:b::", 64, "fe80::2", now, 10, 10, 10); id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", ++now, 10, NM_RDISC_PREFERENCE_HIGH); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10); - nm_fake_rdisc_add_route (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 15); + nm_fake_rdisc_add_prefix (rdisc, id, "2001:db8:a:a::", 64, "fe80::1", now, 10, 10, 15); g_signal_connect (rdisc, NM_RDISC_CONFIG_CHANGED, @@ -380,7 +376,6 @@ test_dns_solicit_loop_rs_sent (NMFakeRDisc *rdisc, TestData *data) id = nm_fake_rdisc_add_ra (rdisc, 0, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 10, NM_RDISC_PREFERENCE_MEDIUM); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10); nm_fake_rdisc_emit_new_ras (rdisc); } else if (data->rs_counter >= 6) { @@ -410,7 +405,6 @@ test_dns_solicit_loop (void) id = nm_fake_rdisc_add_ra (rdisc, 1, NM_RDISC_DHCP_LEVEL_NONE, 4, 1500); g_assert (id); nm_fake_rdisc_add_gateway (rdisc, id, "fe80::1", now, 10, NM_RDISC_PREFERENCE_LOW); - nm_fake_rdisc_add_address (rdisc, id, "2001:db8:a:a::1", now, 10, 10); nm_fake_rdisc_add_dns_server (rdisc, id, "2001:db8:c:c::1", now, 6); g_signal_connect (rdisc, diff --git a/src/rdisc/tests/test-rdisc-linux.c b/src/rdisc/tests/test-rdisc-linux.c index eddb3b0e..b93c50a7 100644 --- a/src/rdisc/tests/test-rdisc-linux.c +++ b/src/rdisc/tests/test-rdisc-linux.c @@ -25,7 +25,7 @@ #include "nm-rdisc.h" #include "nm-lndp-rdisc.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-linux-platform.h" @@ -40,6 +40,8 @@ main (int argc, char **argv) NMRDisc *rdisc; int ifindex = 1; const char *ifname; + NMUtilsIPv6IfaceId iid = { }; + GError *error = NULL; nmtst_init_with_logging (&argc, &argv, NULL, "DEFAULT"); @@ -60,12 +62,19 @@ main (int argc, char **argv) return EXIT_FAILURE; } - rdisc = nm_lndp_rdisc_new (ifindex, ifname); + rdisc = nm_lndp_rdisc_new (ifindex, + ifname, + "8ce666e8-d34d-4fb1-b858-f15a7al28086", + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, + &error); if (!rdisc) { - g_print ("Failed to create NMRDisc instance\n"); + g_print ("Failed to create NMRDisc instance: %s\n", error->message); + g_error_free (error); return EXIT_FAILURE; } + iid.id_u8[7] = 1; + nm_rdisc_set_iid (rdisc, iid); nm_rdisc_start (rdisc); g_main_loop_run (loop); diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index 8d9252a5..ee1c6202 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -23,34 +23,85 @@ #include #include -#include -#include -#include - +#include "nm-default.h" #include "nm-dbus-interface.h" -#include "nm-logging.h" #include "nm-agent-manager.h" #include "nm-secret-agent.h" #include "nm-auth-utils.h" -#include "nm-dbus-glib-types.h" -#include "nm-auth-utils.h" #include "nm-setting-vpn.h" -#include "nm-setting-connection.h" #include "nm-enum-types.h" #include "nm-auth-manager.h" -#include "nm-dbus-manager.h" +#include "nm-bus-manager.h" #include "nm-session-monitor.h" #include "nm-simple-connection.h" #include "NetworkManagerUtils.h" +#include "nm-core-internal.h" + +#include "nmdbus-agent-manager.h" + +NM_DEFINE_SINGLETON_INSTANCE (NMAgentManager); + +#define _NMLOG_PREFIX_NAME "agent-manager" +#define _NMLOG_DOMAIN LOGD_AGENTS +#define _NMLOG(level, agent, ...) \ + G_STMT_START { \ + if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \ + char __prefix1[32]; \ + char __prefix2[128]; \ + NMSecretAgent *__agent = (agent); \ + \ + if (!(self)) \ + g_snprintf (__prefix1, sizeof (__prefix1), "%s%s", ""_NMLOG_PREFIX_NAME"", "[]"); \ + else if ((self) != singleton_instance) \ + g_snprintf (__prefix1, sizeof (__prefix1), "%s[%p]", ""_NMLOG_PREFIX_NAME"", (self)); \ + else \ + g_strlcpy (__prefix1, _NMLOG_PREFIX_NAME, sizeof (__prefix1)); \ + if (__agent) { \ + g_snprintf (__prefix2, sizeof (__prefix2), \ + ": req[%p, %s]", \ + __agent, \ + nm_secret_agent_get_description (__agent)); \ + } else \ + __prefix2[0] = '\0'; \ + _nm_log ((level), (_NMLOG_DOMAIN), 0, \ + "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + __prefix1, __prefix2 _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } G_STMT_END + +#define LOG_REQ_FMT "[%p/%s%s%s%s%s%s]" +#define LOG_REQ_ARG(req) \ + (req), \ + NM_PRINT_FMT_QUOTE_STRING ((req)->detail), \ + NM_PRINT_FMT_QUOTED (((req)->request_type == REQUEST_TYPE_CON_GET) && (req)->con.get.setting_name, \ + "/\"", (req)->con.get.setting_name, "\"", \ + ((req)->request_type == REQUEST_TYPE_CON_GET ? "/(none)" : _request_type_to_string ((req)->request_type, FALSE))) + +typedef enum { + REQUEST_TYPE_INVALID, + REQUEST_TYPE_CON_GET, + REQUEST_TYPE_CON_SAVE, + REQUEST_TYPE_CON_DEL, +} RequestType; + +static const char * +_request_type_to_string (RequestType request_type, gboolean verbose) +{ + switch (request_type) { + case REQUEST_TYPE_CON_GET: return verbose ? "getting" : "get"; + case REQUEST_TYPE_CON_SAVE: return verbose ? "saving" : "sav"; + case REQUEST_TYPE_CON_DEL: return verbose ? "deleting" : "del"; + default: return "??"; + } +} -G_DEFINE_TYPE (NMAgentManager, nm_agent_manager, G_TYPE_OBJECT) +G_DEFINE_TYPE (NMAgentManager, nm_agent_manager, NM_TYPE_EXPORTED_OBJECT) #define NM_AGENT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ NM_TYPE_AGENT_MANAGER, \ NMAgentManagerPrivate)) typedef struct { - NMDBusManager *dbus_mgr; NMAuthManager *auth_mgr; /* Auth chains for checking agent permissions */ @@ -72,7 +123,7 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; -typedef struct _Request Request; +typedef struct _NMAgentManagerCallId Request; static void request_add_agent (Request *req, NMSecretAgent *agent); @@ -80,19 +131,11 @@ static void request_remove_agent (Request *req, NMSecretAgent *agent, GSList **p static void request_next_agent (Request *req); -static void impl_agent_manager_register (NMAgentManager *self, - const char *identifier, - DBusGMethodInvocation *context); - -static void impl_agent_manager_register_with_capabilities (NMAgentManager *self, - const char *identifier, - NMSecretAgentCapabilities capabilities, - DBusGMethodInvocation *context); +static void _con_get_request_start (Request *req); +static void _con_save_request_start (Request *req); +static void _con_del_request_start (Request *req); -static void impl_agent_manager_unregister (NMAgentManager *self, - DBusGMethodInvocation *context); - -#include "nm-agent-manager-glue.h" +static gboolean _con_get_try_complete_early (Request *req); /*************************************************************/ @@ -112,12 +155,11 @@ remove_agent (NMAgentManager *self, const char *owner) if (!agent) return FALSE; - nm_log_dbg (LOGD_AGENTS, "(%s) agent unregistered or disappeared", - nm_secret_agent_get_description (agent)); + _LOGD (agent, "agent unregistered or disappeared"); /* Remove this agent from any in-progress secrets requests */ g_hash_table_iter_init (&iter, priv->requests); - while (g_hash_table_iter_next (&iter, NULL, &data)) + while (g_hash_table_iter_next (&iter, &data, NULL)) request_remove_agent ((Request *) data, agent, &pending_reqs); /* We cannot call request_next_agent() from from within hash iterating loop, @@ -132,6 +174,17 @@ remove_agent (NMAgentManager *self, const char *owner) return TRUE; } +/* Call this *after* calling request_next_agent() */ +static void +maybe_remove_agent_on_error (NMSecretAgent *agent, + GError *error) +{ + if ( g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED) + || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_DISCONNECTED) + || g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER)) + remove_agent (nm_agent_manager_get (), nm_secret_agent_get_dbus_owner (agent)); +} + /*************************************************************/ static gboolean @@ -192,7 +245,7 @@ validate_identifier (const char *identifier, GError **error) static void agent_register_permissions_done (NMAuthChain *chain, GError *error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, gpointer user_data) { NMAgentManager *self = NM_AGENT_MANAGER (user_data); @@ -213,8 +266,7 @@ agent_register_permissions_done (NMAuthChain *chain, NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED, "Failed to request agent permissions: (%d) %s", error->code, error->message); - dbus_g_method_return_error (context, local); - g_error_free (local); + g_dbus_method_invocation_take_error (context, local); } else { agent = nm_auth_chain_steal_data (chain, "agent"); g_assert (agent); @@ -229,16 +281,15 @@ agent_register_permissions_done (NMAuthChain *chain, sender = nm_secret_agent_get_dbus_owner (agent); g_hash_table_insert (priv->agents, g_strdup (sender), agent); - nm_log_dbg (LOGD_AGENTS, "(%s) agent registered", - nm_secret_agent_get_description (agent)); - dbus_g_method_return (context); + _LOGD (agent, "agent registered"); + g_dbus_method_invocation_return_value (context, NULL); /* Signal an agent was registered */ g_signal_emit (self, signals[AGENT_REGISTERED], 0, agent); /* Add this agent to any in-progress secrets requests */ g_hash_table_iter_init (&iter, priv->requests); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &req)) + while (g_hash_table_iter_next (&iter, (gpointer) &req, NULL)) request_add_agent (req, agent); } @@ -263,16 +314,24 @@ find_agent_by_identifier_and_uid (NMAgentManager *self, return NULL; } +static void +agent_disconnected_cb (NMSecretAgent *agent, gpointer user_data) +{ + /* The agent quit, so remove it and let interested clients know */ + remove_agent (NM_AGENT_MANAGER (user_data), + nm_secret_agent_get_dbus_owner (agent)); +} + static void impl_agent_manager_register_with_capabilities (NMAgentManager *self, + GDBusMethodInvocation *context, const char *identifier, - NMSecretAgentCapabilities capabilities, - DBusGMethodInvocation *context) + guint32 capabilities) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); NMAuthSubject *subject; gulong sender_uid = G_MAXULONG; - GError *error = NULL, *local = NULL; + GError *error = NULL; NMSecretAgent *agent; NMAuthChain *chain; @@ -285,17 +344,6 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self, } sender_uid = nm_auth_subject_get_unix_process_uid (subject); - if ( 0 != sender_uid - && !nm_session_monitor_uid_has_session (nm_session_monitor_get (), - sender_uid, - NULL, - &local)) { - error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, - NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED, - local && local->message ? local->message : "Session not found"); - goto done; - } - /* Validate the identifier */ if (!validate_identifier (identifier, &error)) goto done; @@ -316,9 +364,10 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self, "Failed to initialize the agent"); goto done; } + g_signal_connect (agent, NM_SECRET_AGENT_DISCONNECTED, + G_CALLBACK (agent_disconnected_cb), self); - nm_log_dbg (LOGD_AGENTS, "(%s) requesting permissions", - nm_secret_agent_get_description (agent)); + _LOGD (agent, "requesting permissions"); /* Kick off permissions requests for this agent */ chain = nm_auth_chain_new_subject (subject, context, agent_register_permissions_done, self); @@ -337,33 +386,30 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self, done: if (error) - dbus_g_method_return_error (context, error); - g_clear_error (&error); - g_clear_error (&local); + g_dbus_method_invocation_take_error (context, error); g_clear_object (&subject); } static void impl_agent_manager_register (NMAgentManager *self, - const char *identifier, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + const char *identifier) { - impl_agent_manager_register_with_capabilities (self, identifier, 0, context); + impl_agent_manager_register_with_capabilities (self, context, identifier, 0); } static void impl_agent_manager_unregister (NMAgentManager *self, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context) { - NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); GError *error = NULL; char *sender = NULL; - if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, - context, - &sender, - NULL, - NULL)) { + if (!nm_bus_manager_get_caller_info (nm_bus_manager_get (), + context, + &sender, + NULL, + NULL)) { error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED, "Unable to determine request sender."); @@ -378,137 +424,188 @@ impl_agent_manager_unregister (NMAgentManager *self, goto done; } - dbus_g_method_return (context); + g_dbus_method_invocation_return_value (context, NULL); done: if (error) - dbus_g_method_return_error (context, error); - g_clear_error (&error); + g_dbus_method_invocation_take_error (context, error); g_free (sender); } /*************************************************************/ -typedef void (*RequestCompleteFunc) (Request *req, - GHashTable *secrets, - const char *agent_dbus_owner, - const char *agent_username, - GError *error, - gpointer user_data); -typedef gboolean (*RequestAddAgentFunc) (Request *req, NMSecretAgent *agent); -typedef void (*RequestNextFunc) (Request *req); -typedef void (*RequestCancelFunc) (Request *req); - -/* Basic secrets request structure */ -struct _Request { - guint32 reqid; +struct _NMAgentManagerCallId { + NMAgentManager *self; + + RequestType request_type; + char *detail; - char *verb; NMAuthSubject *subject; /* Current agent being asked for secrets */ NMSecretAgent *current; - gconstpointer current_call_id; + NMSecretAgentCallId current_call_id; /* Stores the sorted list of NMSecretAgents which will be asked for secrets */ GSList *pending; - /* Stores the list of NMSecretAgent hashes that we've already - * asked for secrets, so that we don't ask the same agent twice - * if it quits and re-registers during this secrets request. - */ - GSList *asked; + guint idle_id; - NMAuthChain *chain; + union { + struct { + char *path; + NMConnection *connection; - guint32 idle_id; + NMAuthChain *chain; - RequestAddAgentFunc add_agent_callback; - RequestCancelFunc cancel_callback; - RequestNextFunc next_callback; - RequestCompleteFunc complete_callback; - gpointer complete_callback_data; - gboolean completed; + /* Whether the agent currently being asked for secrets + * has the system.modify privilege. + */ + gboolean current_has_modify; - GDestroyNotify free_func; -}; + union { + struct { + NMSecretAgentGetSecretsFlags flags; + char *setting_name; + char **hints; -static guint32 next_req_id = 1; + GVariant *existing_secrets; + + NMAgentSecretsResultFunc callback; + gpointer callback_data; + } get; + }; + } con; + }; +}; static Request * -request_new (gsize struct_size, +request_new (NMAgentManager *self, + RequestType request_type, const char *detail, - const char *verb, - NMAuthSubject *subject, - RequestCompleteFunc complete_callback, - gpointer complete_callback_data, - RequestAddAgentFunc add_agent_callback, - RequestNextFunc next_callback, - RequestCancelFunc cancel_callback, - GDestroyNotify free_func) + NMAuthSubject *subject) { Request *req; - req = g_malloc0 (struct_size); - req->reqid = next_req_id++; + req = g_slice_new0 (Request); + req->self = g_object_ref (self); + req->request_type = request_type; req->detail = g_strdup (detail); - req->verb = g_strdup (verb); req->subject = g_object_ref (subject); - req->complete_callback = complete_callback; - req->complete_callback_data = complete_callback_data; - req->add_agent_callback = add_agent_callback, - req->next_callback = next_callback; - req->cancel_callback = cancel_callback; - req->free_func = free_func; return req; } static void request_free (Request *req) { - if (req->free_func) - req->free_func ((gpointer) req); + switch (req->request_type) { + case REQUEST_TYPE_CON_GET: + case REQUEST_TYPE_CON_SAVE: + case REQUEST_TYPE_CON_DEL: + g_object_unref (req->con.connection); + g_free (req->con.path); + if (req->con.chain) + nm_auth_chain_unref (req->con.chain); + if (req->request_type == REQUEST_TYPE_CON_GET) { + g_free (req->con.get.setting_name); + g_strfreev (req->con.get.hints); + if (req->con.get.existing_secrets) + g_variant_unref (req->con.get.existing_secrets); + } + break; + default: + g_assert_not_reached (); + } if (req->idle_id) g_source_remove (req->idle_id); - if (!req->completed && req->cancel_callback) - req->cancel_callback (req); - - if (req->chain) - nm_auth_chain_unref (req->chain); + if (req->current && req->current_call_id) { + /* cancel-secrets invokes the done-callback synchronously -- in which case + * the handler just return. + * Hence, we can proceed to free @req... */ + nm_secret_agent_cancel_secrets (req->current, req->current_call_id); + } g_object_unref (req->subject); g_free (req->detail); - g_free (req->verb); g_slist_free_full (req->pending, g_object_unref); - g_slist_free (req->asked); + + g_object_unref (req->self); + + if (req->current) + g_object_unref (req->current); + memset (req, 0, sizeof (Request)); - g_free (req); + g_slice_free (Request, req); } static void -req_complete_success (Request *req, - GHashTable *secrets, +req_complete_release (Request *req, + GVariant *secrets, const char *agent_dbus_owner, - const char *agent_uname) + const char *agent_username, + GError *error) +{ + NMAgentManager *self = req->self; + + switch (req->request_type) { + case REQUEST_TYPE_CON_GET: + req->con.get.callback (self, + req, + agent_dbus_owner, + agent_username, + req->con.current_has_modify, + req->con.get.setting_name, + req->con.get.flags, + error ? NULL : secrets, + error, + req->con.get.callback_data); + + break; + case REQUEST_TYPE_CON_SAVE: + case REQUEST_TYPE_CON_DEL: + break; + default: + g_return_if_reached (); + } + + request_free (req); +} + +static void +req_complete_cancel (Request *req, gboolean is_disposing) +{ + gs_free_error GError *error = NULL; + + nm_assert (req && req->self); + nm_assert (!g_hash_table_contains (NM_AGENT_MANAGER_GET_PRIVATE (req->self)->requests, req)); + + nm_utils_error_set_cancelled (&error, is_disposing, "NMAgentManager"); + req_complete_release (req, NULL, NULL, NULL, error); +} + +static void +req_complete (Request *req, + GVariant *secrets, + const char *agent_dbus_owner, + const char *agent_username, + GError *error) { - req->completed = TRUE; - req->complete_callback (req, - secrets, - agent_dbus_owner, - agent_uname, - NULL, - req->complete_callback_data); + NMAgentManager *self = req->self; + NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); + + if (!g_hash_table_remove (priv->requests, req)) + g_return_if_reached (); + req_complete_release (req, secrets, agent_dbus_owner, agent_username, error); } static void req_complete_error (Request *req, GError *error) { - req->completed = TRUE; - req->complete_callback (req, NULL, NULL, NULL, error, req->complete_callback_data); + req_complete (req, NULL, NULL, NULL, error); } static gint @@ -535,12 +632,8 @@ agent_compare_func (gconstpointer aa, gconstpointer bb, gpointer user_data) } /* Prefer agents in active sessions */ - a_active = nm_session_monitor_uid_active (nm_session_monitor_get (), - nm_secret_agent_get_owner_uid (a), - NULL); - b_active = nm_session_monitor_uid_active (nm_session_monitor_get (), - nm_secret_agent_get_owner_uid (b), - NULL); + a_active = nm_session_monitor_session_exists (nm_session_monitor_get (), nm_secret_agent_get_owner_uid (a), TRUE); + b_active = nm_session_monitor_session_exists (nm_session_monitor_get (), nm_secret_agent_get_owner_uid (b), TRUE); if (a_active && !b_active) return -1; else if (a_active == b_active) @@ -554,14 +647,26 @@ agent_compare_func (gconstpointer aa, gconstpointer bb, gpointer user_data) static void request_add_agent (Request *req, NMSecretAgent *agent) { + NMAgentManager *self; + g_return_if_fail (req != NULL); g_return_if_fail (agent != NULL); - if (g_slist_find (req->asked, GUINT_TO_POINTER (nm_secret_agent_get_hash (agent)))) - return; + self = req->self; - if (req->add_agent_callback && !req->add_agent_callback (req, agent)) - return; + if (req->request_type == REQUEST_TYPE_CON_GET) { + NMAuthSubject *subject = nm_secret_agent_get_subject (agent); + + /* Ensure the caller's username exists in the connection's permissions, + * or that the permissions is empty (ie, visible by everyone). + */ + if (!nm_auth_is_subject_in_acl (req->con.connection, subject, NULL)) { + _LOGD (agent, "agent ignored for secrets request "LOG_REQ_FMT" (not in ACL)", + LOG_REQ_ARG (req)); + /* Connection not visible to this agent's user */ + return; + } + } /* If the request should filter agents by UID, do that now */ if (nm_auth_subject_is_unix_process (req->subject)) { @@ -570,18 +675,16 @@ request_add_agent (Request *req, NMSecretAgent *agent) agent_uid = nm_secret_agent_get_owner_uid (agent); subject_uid = nm_auth_subject_get_unix_process_uid (req->subject); if (agent_uid != subject_uid) { - nm_log_dbg (LOGD_AGENTS, "(%s) agent ignored for secrets request %p/%s " - "(uid %ld not required %ld)", - nm_secret_agent_get_description (agent), - req, req->detail, - (long)agent_uid, (long)subject_uid); + _LOGD (agent, "agent ignored for secrets request "LOG_REQ_FMT" " + "(uid %ld not required %ld)", + LOG_REQ_ARG (req), + (long) agent_uid, (long) subject_uid); return; } } - nm_log_dbg (LOGD_AGENTS, "(%s) agent allowed for secrets request %p/%s", - nm_secret_agent_get_description (agent), - req, req->detail); + _LOGD (agent, "agent allowed for secrets request "LOG_REQ_FMT, + LOG_REQ_ARG (req)); /* Add this agent to the list, sorted appropriately */ req->pending = g_slist_insert_sorted_with_data (req->pending, @@ -605,25 +708,41 @@ request_add_agents (NMAgentManager *self, Request *req) static void request_next_agent (Request *req) { + NMAgentManager *self; GError *error = NULL; - req->current_call_id = NULL; - if (req->current) - g_object_unref (req->current); + self = req->self; + + if (req->current) { + if (req->current_call_id) + nm_secret_agent_cancel_secrets (req->current, req->current_call_id); + g_clear_object (&req->current); + } + g_warn_if_fail (!req->current_call_id); if (req->pending) { /* Send the request to the next agent */ req->current = req->pending->data; req->pending = g_slist_remove (req->pending, req->current); - nm_log_dbg (LOGD_AGENTS, "(%s) agent %s secrets for request %p/%s", - nm_secret_agent_get_description (req->current), - req->verb, req, req->detail); - - req->next_callback (req); + _LOGD (req->current, "agent %s secrets for request "LOG_REQ_FMT, + _request_type_to_string (req->request_type, TRUE), + LOG_REQ_ARG (req)); + + switch (req->request_type) { + case REQUEST_TYPE_CON_GET: + _con_get_request_start (req); + break; + case REQUEST_TYPE_CON_SAVE: + _con_save_request_start (req); + break; + case REQUEST_TYPE_CON_DEL: + _con_del_request_start (req); + break; + default: + g_assert_not_reached (); + } } else { - req->current = NULL; - /* No more secret agents are available to fulfill this secrets request */ error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_NO_SECRETS, @@ -636,25 +755,41 @@ request_next_agent (Request *req) static void request_remove_agent (Request *req, NMSecretAgent *agent, GSList **pending_reqs) { + NMAgentManager *self; + g_return_if_fail (req != NULL); g_return_if_fail (agent != NULL); - req->pending = g_slist_remove (req->pending, agent); + self = req->self; if (agent == req->current) { - nm_log_dbg (LOGD_AGENTS, "(%s) current agent removed from secrets request %p/%s", - nm_secret_agent_get_description (agent), req, req->detail); - - if (req->chain) { - /* This cancels the pending authorization requests. */ - nm_auth_chain_unref (req->chain); - req->chain = NULL; + nm_assert (!g_slist_find (req->pending, agent)); + + _LOGD (agent, "current agent removed from secrets request "LOG_REQ_FMT, + LOG_REQ_ARG (req)); + + switch (req->request_type) { + case REQUEST_TYPE_CON_GET: + case REQUEST_TYPE_CON_SAVE: + case REQUEST_TYPE_CON_DEL: + if (req->con.chain) { + /* This cancels the pending authorization requests. */ + nm_auth_chain_unref (req->con.chain); + req->con.chain = NULL; + } + break; + default: + g_assert_not_reached (); } *pending_reqs = g_slist_prepend (*pending_reqs, req); - } else { - nm_log_dbg (LOGD_AGENTS, "(%s) agent removed from secrets request %p/%s", - nm_secret_agent_get_description (agent), req, req->detail); + } else if (g_slist_find (req->pending, agent)) { + req->pending = g_slist_remove (req->pending, agent); + + _LOGD (agent, "agent removed from secrets request "LOG_REQ_FMT, + LOG_REQ_ARG (req)); + + g_object_unref (agent); } } @@ -664,190 +799,87 @@ request_start (gpointer user_data) Request *req = user_data; req->idle_id = 0; - request_next_agent (req); - return FALSE; -} - -/*************************************************************/ - -/* Request subclass for connection secrets */ -typedef struct { - Request parent; - - NMSecretAgentGetSecretsFlags flags; - NMConnection *connection; - char *setting_name; - char **hints; - - GHashTable *existing_secrets; - NMAgentSecretsResultFunc callback; - gpointer callback_data; - gpointer other_data2; - gpointer other_data3; - - /* Whether the agent currently being asked for secrets - * has the system.modify privilege. - */ - gboolean current_has_modify; -} ConnectionRequest; - -static void -connection_request_free (gpointer data) -{ - ConnectionRequest *req = data; - - g_object_unref (req->connection); - g_free (req->setting_name); - g_strfreev (req->hints); - if (req->existing_secrets) - g_hash_table_unref (req->existing_secrets); -} - -static gboolean -connection_request_add_agent (Request *parent, NMSecretAgent *agent) -{ - ConnectionRequest *req = (ConnectionRequest *) parent; - NMAuthSubject *subject = nm_secret_agent_get_subject(agent); - - /* Ensure the caller's username exists in the connection's permissions, - * or that the permissions is empty (ie, visible by everyone). - */ - if (!nm_auth_is_subject_in_acl (req->connection, nm_session_monitor_get (), subject, NULL)) { - nm_log_dbg (LOGD_AGENTS, "(%s) agent ignored for secrets request %p/%s (not in ACL)", - nm_secret_agent_get_description (agent), - parent, parent->detail); - /* Connection not visible to this agent's user */ - return FALSE; + switch (req->request_type) { + case REQUEST_TYPE_CON_GET: + if (_con_get_try_complete_early (req)) + goto out; + break; + default: + break; } + request_next_agent (req); - return TRUE; -} - -static ConnectionRequest * -connection_request_new_get (NMConnection *connection, - NMAuthSubject *subject, - GHashTable *existing_secrets, - const char *setting_name, - const char *verb, - NMSecretAgentGetSecretsFlags flags, - const char **hints, - NMAgentSecretsResultFunc callback, - gpointer callback_data, - gpointer other_data2, - gpointer other_data3, - RequestCompleteFunc complete_callback, - gpointer complete_callback_data, - RequestNextFunc next_callback, - RequestCancelFunc cancel_callback) -{ - ConnectionRequest *req; - - req = (ConnectionRequest *) request_new (sizeof (ConnectionRequest), - nm_connection_get_id (connection), - verb, - subject, - complete_callback, - complete_callback_data, - connection_request_add_agent, - next_callback, - cancel_callback, - connection_request_free); - g_assert (req); - - req->connection = g_object_ref (connection); - if (existing_secrets) - req->existing_secrets = g_hash_table_ref (existing_secrets); - req->setting_name = g_strdup (setting_name); - req->hints = g_strdupv ((char **) hints); - req->flags = flags; - req->callback = callback; - req->callback_data = callback_data; - req->other_data2 = other_data2; - req->other_data3 = other_data3; - return req; +out: + return FALSE; } -static ConnectionRequest * -connection_request_new_other (NMConnection *connection, - NMAuthSubject *subject, - const char *verb, - RequestCompleteFunc complete_callback, - gpointer complete_callback_data, - RequestNextFunc next_callback) -{ - ConnectionRequest *req; - - req = (ConnectionRequest *) request_new (sizeof (ConnectionRequest), - nm_connection_get_id (connection), - verb, - subject, - complete_callback, - complete_callback_data, - NULL, - next_callback, - NULL, - connection_request_free); - g_assert (req); - req->connection = g_object_ref (connection); - return req; -} +/*************************************************************/ static void -get_done_cb (NMSecretAgent *agent, - gconstpointer call_id, - GHashTable *secrets, - GError *error, - gpointer user_data) +_con_get_request_done (NMSecretAgent *agent, + NMSecretAgentCallId call_id, + GVariant *secrets, + GError *error, + gpointer user_data) { - Request *parent = user_data; - ConnectionRequest *req = user_data; - GHashTable *setting_secrets; + NMAgentManager *self; + Request *req = user_data; + GVariant *setting_secrets; const char *agent_dbus_owner; struct passwd *pw; char *agent_uname = NULL; - g_return_if_fail (call_id == parent->current_call_id); + g_return_if_fail (call_id == req->current_call_id); + g_return_if_fail (agent == req->current); + g_return_if_fail (req->request_type == REQUEST_TYPE_CON_GET); + + self = req->self; + + req->current_call_id = NULL; if (error) { - nm_log_dbg (LOGD_AGENTS, "(%s) agent failed secrets request %p/%s/%s: (%d) %s", - nm_secret_agent_get_description (agent), - req, parent->detail, req->setting_name, - error ? error->code : -1, - (error && error->message) ? error->message : "(unknown)"); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + _LOGD (agent, "get secrets request cancelled: "LOG_REQ_FMT, + LOG_REQ_ARG (req)); + return; + } - if (dbus_g_error_has_name (error, NM_DBUS_INTERFACE_SECRET_AGENT ".UserCanceled")) { + _LOGD (agent, "agent failed secrets request "LOG_REQ_FMT": %s", + LOG_REQ_ARG (req), + error->message); + + if (g_error_matches (error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_USER_CANCELED)) { error = g_error_new_literal (NM_AGENT_MANAGER_ERROR, NM_AGENT_MANAGER_ERROR_USER_CANCELED, "User canceled the secrets request."); - req_complete_error (parent, error); + req_complete_error (req, error); g_error_free (error); } else { - if (parent->current_call_id) { + if (req->current_call_id) { /* Tell the failed agent we're no longer interested. */ - nm_secret_agent_cancel_secrets (parent->current, parent->current_call_id); + nm_secret_agent_cancel_secrets (req->current, req->current_call_id); } /* Try the next agent */ - request_next_agent (parent); + request_next_agent (req); + maybe_remove_agent_on_error (agent, error); } return; } /* Ensure the setting we wanted secrets for got returned and has something in it */ - setting_secrets = g_hash_table_lookup (secrets, req->setting_name); - if (!setting_secrets || !g_hash_table_size (setting_secrets)) { - nm_log_dbg (LOGD_AGENTS, "(%s) agent returned no secrets for request %p/%s/%s", - nm_secret_agent_get_description (agent), - req, parent->detail, req->setting_name); + setting_secrets = g_variant_lookup_value (secrets, req->con.get.setting_name, NM_VARIANT_TYPE_SETTING); + if (!setting_secrets || !g_variant_n_children (setting_secrets)) { + _LOGD (agent, "agent returned no secrets for request "LOG_REQ_FMT, + LOG_REQ_ARG (req)); /* Try the next agent */ - request_next_agent (parent); + request_next_agent (req); return; } - nm_log_dbg (LOGD_AGENTS, "(%s) agent returned secrets for request %p/%s/%s", - nm_secret_agent_get_description (agent), - req, parent->detail, req->setting_name); + _LOGD (agent, "agent returned secrets for request "LOG_REQ_FMT, + LOG_REQ_ARG (req)); /* Get the agent's username */ pw = getpwuid (nm_secret_agent_get_owner_uid (agent)); @@ -858,110 +890,109 @@ get_done_cb (NMSecretAgent *agent, } agent_dbus_owner = nm_secret_agent_get_dbus_owner (agent); - req_complete_success (parent, secrets, agent_dbus_owner, agent_uname); + req_complete (req, secrets, agent_dbus_owner, agent_uname, NULL); g_free (agent_uname); } static void -set_secrets_not_required (NMConnection *connection, GHashTable *hash) +set_secrets_not_required (NMConnection *connection, GVariant *dict) { - GHashTableIter iter, setting_iter; + GVariantIter iter, setting_iter; const char *setting_name = NULL; - GHashTable *setting_hash = NULL; + GVariant *setting_dict = NULL; - /* Iterate through the settings hashes */ - g_hash_table_iter_init (&iter, hash); - while (g_hash_table_iter_next (&iter, - (gpointer *) &setting_name, - (gpointer *) &setting_hash)) { + /* Iterate through the settings dicts */ + g_variant_iter_init (&iter, dict); + while (g_variant_iter_next (&iter, "{&s@a{sv}}", &setting_name, &setting_dict)) { const char *key_name = NULL; NMSetting *setting; - GValue *val; + GVariant *val; setting = nm_connection_get_setting_by_name (connection, setting_name); if (setting) { /* Now through each secret in the setting and mark it as not required */ - g_hash_table_iter_init (&setting_iter, setting_hash); - while (g_hash_table_iter_next (&setting_iter, (gpointer *) &key_name, (gpointer *) &val)) { + g_variant_iter_init (&setting_iter, setting_dict); + while (g_variant_iter_next (&setting_iter, "{&sv}", &key_name, &val)) { /* For each secret, set the flag that it's not required; VPN * secrets need slightly different treatment here since the - * "secrets" property is actually a hash table of secrets. + * "secrets" property is actually a dictionary of secrets. */ if ( strcmp (setting_name, NM_SETTING_VPN_SETTING_NAME) == 0 - && strcmp (key_name, NM_SETTING_VPN_SECRETS) == 0) { - GHashTableIter vpn_secret_iter; - const char *secret_name; + && strcmp (key_name, NM_SETTING_VPN_SECRETS) == 0 + && g_variant_is_of_type (val, G_VARIANT_TYPE ("a{ss}"))) { + GVariantIter vpn_secret_iter; + const char *secret_name, *secret; - g_hash_table_iter_init (&vpn_secret_iter, g_value_get_boxed (val)); - while (g_hash_table_iter_next (&vpn_secret_iter, (gpointer *) &secret_name, NULL)) + g_variant_iter_init (&vpn_secret_iter, val); + while (g_variant_iter_next (&vpn_secret_iter, "{&s&s}", &secret_name, &secret)) nm_setting_set_secret_flags (setting, secret_name, NM_SETTING_SECRET_FLAG_NOT_REQUIRED, NULL); } else nm_setting_set_secret_flags (setting, key_name, NM_SETTING_SECRET_FLAG_NOT_REQUIRED, NULL); + g_variant_unref (val); } } } } static void -get_agent_request_secrets (ConnectionRequest *req, gboolean include_system_secrets) +_con_get_request_start_proceed (Request *req, gboolean include_system_secrets) { - Request *parent = (Request *) req; NMConnection *tmp; - tmp = nm_simple_connection_new_clone (req->connection); + g_return_if_fail (req->request_type == REQUEST_TYPE_CON_GET); + + tmp = nm_simple_connection_new_clone (req->con.connection); nm_connection_clear_secrets (tmp); if (include_system_secrets) { - if (req->existing_secrets) { - GVariant *secrets_dict; - - secrets_dict = nm_utils_connection_hash_to_dict (req->existing_secrets); - (void) nm_connection_update_secrets (tmp, req->setting_name, secrets_dict, NULL); - g_variant_unref (secrets_dict); - } + if (req->con.get.existing_secrets) + (void) nm_connection_update_secrets (tmp, req->con.get.setting_name, req->con.get.existing_secrets, NULL); } else { /* Update secret flags in the temporary connection to indicate that * the system secrets we're not sending to the agent aren't required, * so the agent can properly validate UI controls and such. */ - if (req->existing_secrets) - set_secrets_not_required (tmp, req->existing_secrets); + if (req->con.get.existing_secrets) + set_secrets_not_required (tmp, req->con.get.existing_secrets); } - parent->current_call_id = nm_secret_agent_get_secrets (parent->current, - tmp, - req->setting_name, - (const char **) req->hints, - req->flags, - get_done_cb, - req); - if (parent->current_call_id == NULL) { - /* Shouldn't hit this, but handle it anyway */ - g_warn_if_fail (parent->current_call_id != NULL); - request_next_agent (parent); + req->current_call_id = nm_secret_agent_get_secrets (req->current, + req->con.path, + tmp, + req->con.get.setting_name, + (const char **) req->con.get.hints, + req->con.get.flags, + _con_get_request_done, + req); + if (!req->current_call_id) { + g_warn_if_reached (); + request_next_agent (req); } g_object_unref (tmp); } static void -get_agent_modify_auth_cb (NMAuthChain *chain, - GError *error, - DBusGMethodInvocation *context, - gpointer user_data) +_con_get_request_start_validated (NMAuthChain *chain, + GError *error, + GDBusMethodInvocation *context, + gpointer user_data) { - Request *parent = user_data; - ConnectionRequest *req = user_data; + NMAgentManager *self; + Request *req = user_data; const char *perm; - parent->chain = NULL; + g_return_if_fail (req->request_type == REQUEST_TYPE_CON_GET); + + self = req->self; + + req->con.chain = NULL; if (error) { - nm_log_dbg (LOGD_AGENTS, "(%s) agent %p/%s/%s MODIFY check error: (%d) %s", - nm_secret_agent_get_description (parent->current), - req, parent->detail, req->setting_name, - error->code, error->message ? error->message : "(unknown)"); + _LOGD (req->current, "agent "LOG_REQ_FMT" MODIFY check error: (%d) %s", + LOG_REQ_ARG (req), + error->code, error->message ? error->message : "(unknown)"); /* Try the next agent */ - request_next_agent (parent); + request_next_agent (req); } else { /* If the agent obtained the 'modify' permission, we send all system secrets * to it. If it didn't, we still ask it for secrets, but we don't send @@ -970,25 +1001,24 @@ get_agent_modify_auth_cb (NMAuthChain *chain, perm = nm_auth_chain_get_data (chain, "perm"); g_assert (perm); if (nm_auth_chain_get_result (chain, perm) == NM_AUTH_CALL_RESULT_YES) - req->current_has_modify = TRUE; + req->con.current_has_modify = TRUE; - nm_log_dbg (LOGD_AGENTS, "(%s) agent %p/%s/%s MODIFY check result %s", - nm_secret_agent_get_description (parent->current), - req, parent->detail, req->setting_name, - req->current_has_modify ? "YES" : "NO"); + _LOGD (req->current, "agent "LOG_REQ_FMT" MODIFY check result %s", + LOG_REQ_ARG (req), + req->con.current_has_modify ? "YES" : "NO"); - get_agent_request_secrets (req, req->current_has_modify); + _con_get_request_start_proceed (req, req->con.current_has_modify); } nm_auth_chain_unref (chain); } static void -check_system_secrets_cb (NMSetting *setting, - const char *key, - const GValue *value, - GParamFlags flags, - gpointer user_data) +has_system_secrets_check (NMSetting *setting, + const char *key, + const GValue *value, + GParamFlags flags, + gpointer user_data) { NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; gboolean *has_system = user_data; @@ -1022,20 +1052,22 @@ has_system_secrets (NMConnection *connection) { gboolean has_system = FALSE; - nm_connection_for_each_setting_value (connection, check_system_secrets_cb, &has_system); + nm_connection_for_each_setting_value (connection, has_system_secrets_check, &has_system); return has_system; } static void -get_next_cb (Request *parent) +_con_get_request_start (Request *req) { - ConnectionRequest *req = (ConnectionRequest *) parent; + NMAgentManager *self; NMSettingConnection *s_con; const char *agent_dbus_owner, *perm; - req->current_has_modify = FALSE; + self = req->self; + + req->con.current_has_modify = FALSE; - agent_dbus_owner = nm_secret_agent_get_dbus_owner (parent->current); + agent_dbus_owner = nm_secret_agent_get_dbus_owner (req->current); /* If the request flags allow user interaction, and there are existing * system secrets (or blank secrets that are supposed to be system-owned), @@ -1043,168 +1075,144 @@ get_next_cb (Request *parent) * secrets to the agent. We shouldn't leak system-owned secrets to * unprivileged users. */ - if ( (req->flags != NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) - && (req->existing_secrets || has_system_secrets (req->connection))) { - nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) request has system secrets; checking agent %s for MODIFY", - req, parent->detail, req->setting_name, agent_dbus_owner); + if ( (req->con.get.flags != NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) + && (req->con.get.existing_secrets || has_system_secrets (req->con.connection))) { + _LOGD (NULL, "("LOG_REQ_FMT") request has system secrets; checking agent %s for MODIFY", + LOG_REQ_ARG (req), agent_dbus_owner); - parent->chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (parent->current), - NULL, - get_agent_modify_auth_cb, - req); - g_assert (parent->chain); + req->con.chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (req->current), + NULL, + _con_get_request_start_validated, + req); + g_assert (req->con.chain); /* If the caller is the only user in the connection's permissions, then * we use the 'modify.own' permission instead of 'modify.system'. If the * request affects more than just the caller, require 'modify.system'. */ - s_con = nm_connection_get_setting_connection (req->connection); + s_con = nm_connection_get_setting_connection (req->con.connection); g_assert (s_con); if (nm_setting_connection_get_num_permissions (s_con) == 1) perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN; else perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM; - nm_auth_chain_set_data (parent->chain, "perm", (gpointer) perm, NULL); + nm_auth_chain_set_data (req->con.chain, "perm", (gpointer) perm, NULL); - nm_auth_chain_add_call (parent->chain, perm, TRUE); + nm_auth_chain_add_call (req->con.chain, perm, TRUE); } else { - nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) requesting user-owned secrets from agent %s", - req, parent->detail, req->setting_name, agent_dbus_owner); + _LOGD (NULL, "("LOG_REQ_FMT") requesting user-owned secrets from agent %s", + LOG_REQ_ARG (req), agent_dbus_owner); - get_agent_request_secrets (req, FALSE); + _con_get_request_start_proceed (req, FALSE); } } static gboolean -get_start (gpointer user_data) +_con_get_try_complete_early (Request *req) { - Request *parent = user_data; - ConnectionRequest *req = user_data; - GHashTable *setting_secrets = NULL; + NMAgentManager *self; + gs_unref_variant GVariant *setting_secrets = NULL; + gs_unref_object NMConnection *tmp = NULL; + GError *error = NULL; - parent->idle_id = 0; + self = req->self; /* Check if there are any existing secrets */ - if (req->existing_secrets) - setting_secrets = g_hash_table_lookup (req->existing_secrets, req->setting_name); - - if (setting_secrets && g_hash_table_size (setting_secrets)) { - NMConnection *tmp; - GError *error = NULL; - gboolean new_secrets = (req->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW); - GVariant *secrets_dict; - - /* The connection already had secrets; check if any more are required. - * If no more are required, we're done. If secrets are still needed, - * ask a secret agent for more. This allows admins to provide generic - * secrets but allow additional user-specific ones as well. - */ - tmp = nm_simple_connection_new_clone (req->connection); - g_assert (tmp); + if (req->con.get.existing_secrets) + setting_secrets = g_variant_lookup_value (req->con.get.existing_secrets, req->con.get.setting_name, NM_VARIANT_TYPE_SETTING); - secrets_dict = nm_utils_connection_hash_to_dict (req->existing_secrets); - if (!nm_connection_update_secrets (tmp, req->setting_name, secrets_dict, &error)) { - req_complete_error (parent, error); - g_clear_error (&error); - } else { - /* Do we have everything we need? */ - if ( (req->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM) - || ((nm_connection_need_secrets (tmp, NULL) == NULL) && (new_secrets == FALSE))) { - nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) system settings secrets sufficient", - req, parent->detail, req->setting_name); - - /* Got everything, we're done */ - req_complete_success (parent, req->existing_secrets, NULL, NULL); - } else { - nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) system settings secrets insufficient, asking agents", - req, parent->detail, req->setting_name); - - /* We don't, so ask some agents for additional secrets */ - if ( req->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS - && !parent->pending) { - /* The request initiated from GetSecrets() via DBus, - * don't error out if any secrets are missing. */ - req_complete_success (parent, req->existing_secrets, NULL, NULL); - } else - request_next_agent (parent); - } - } - g_variant_unref (secrets_dict); - g_object_unref (tmp); - } else { - /* Couldn't get secrets from system settings, so now we ask the - * agents for secrets. Let the Agent Manager handle which agents - * we'll ask and in which order. - */ - request_next_agent (parent); - } + if (!setting_secrets || !g_variant_n_children (setting_secrets)) + return FALSE; - return FALSE; -} + /* The connection already had secrets; check if any more are required. + * If no more are required, we're done. If secrets are still needed, + * ask a secret agent for more. This allows admins to provide generic + * secrets but allow additional user-specific ones as well. + */ + tmp = nm_simple_connection_new_clone (req->con.connection); + g_assert (tmp); -static void -get_complete_cb (Request *parent, - GHashTable *secrets, - const char *agent_dbus_owner, - const char *agent_username, - GError *error, - gpointer user_data) -{ - NMAgentManager *self = NM_AGENT_MANAGER (user_data); - NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - ConnectionRequest *req = (ConnectionRequest *) parent; - - /* Send secrets back to the requesting object */ - req->callback (self, - parent->reqid, - agent_dbus_owner, - agent_username, - req->current_has_modify, - req->setting_name, - req->flags, - error ? NULL : secrets, - error, - req->callback_data, - req->other_data2, - req->other_data3); - - g_hash_table_remove (priv->requests, GUINT_TO_POINTER (parent->reqid)); -} + if (!nm_connection_update_secrets (tmp, req->con.get.setting_name, req->con.get.existing_secrets, &error)) { + req_complete_error (req, error); + g_clear_error (&error); + return TRUE; + } + /* Do we have everything we need? */ + if ( NM_FLAGS_HAS (req->con.get.flags, NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM) + || ( (nm_connection_need_secrets (tmp, NULL) == NULL) + && !NM_FLAGS_HAS(req->con.get.flags, NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW))) { + _LOGD (NULL, "("LOG_REQ_FMT") system settings secrets sufficient", + LOG_REQ_ARG (req)); + + /* Got everything, we're done */ + req_complete (req, req->con.get.existing_secrets, NULL, NULL, NULL); + return TRUE; + } -static void -get_cancel_cb (Request *parent) -{ - ConnectionRequest *req = (ConnectionRequest *) parent; + _LOGD (NULL, "("LOG_REQ_FMT") system settings secrets insufficient, asking agents", + LOG_REQ_ARG (req)); + + /* We don't, so ask some agents for additional secrets */ + if ( req->con.get.flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS + && !req->pending) { + /* The request initiated from GetSecrets() via DBus, + * don't error out if any secrets are missing. */ + req_complete (req, req->con.get.existing_secrets, NULL, NULL, NULL); + return TRUE; + } - req->current_has_modify = FALSE; - if (parent->current && parent->current_call_id) - nm_secret_agent_cancel_secrets (parent->current, parent->current_call_id); + /* Couldn't get secrets from system settings, so now we ask the + * agents for secrets. Let the Agent Manager handle which agents + * we'll ask and in which order. + */ + return FALSE; } -guint32 +/** + * nm_agent_manager_get_secrets: + * @self: + * @path: + * @connection: + * @subject: + * @existing_secrets: + * @flags: + * @hints: + * @callback: + * @callback_data: + * + * Requests secrets for a connection. + * + * This function cannot fail. The callback will be invoked + * asynchrnously, but it will always be invoked exactly once. + * Even for cancellation and disposing of @self. In those latter + * cases, the callback is invoked synchrnously during the cancellation/ + * disposal. + * + * Returns: a call-id to cancel the call. + */ +NMAgentManagerCallId nm_agent_manager_get_secrets (NMAgentManager *self, + const char *path, NMConnection *connection, NMAuthSubject *subject, - GHashTable *existing_secrets, + GVariant *existing_secrets, const char *setting_name, NMSecretAgentGetSecretsFlags flags, const char **hints, NMAgentSecretsResultFunc callback, - gpointer callback_data, - gpointer other_data2, - gpointer other_data3) + gpointer callback_data) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - Request *parent; - ConnectionRequest *req; + Request *req; - g_return_val_if_fail (self != NULL, 0); - g_return_val_if_fail (NM_IS_CONNECTION (connection), 0); - g_return_val_if_fail (callback != NULL, 0); + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (path && *path, NULL); + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + g_return_val_if_fail (callback != NULL, NULL); nm_log_dbg (LOGD_SETTINGS, "Secrets requested for connection %s (%s/%s)", - nm_connection_get_path (connection), + path, nm_connection_get_id (connection), setting_name); @@ -1213,224 +1221,221 @@ nm_agent_manager_get_secrets (NMAgentManager *self, * This in turn depends on nm_connection_to_dbus() and nm_setting_to_hash() * both returning NULL if they didn't hash anything. */ + req = request_new (self, + REQUEST_TYPE_CON_GET, + nm_connection_get_id (connection), + subject); + + req->con.path = g_strdup (path); + req->con.connection = g_object_ref (connection); + if (existing_secrets) + req->con.get.existing_secrets = g_variant_ref (existing_secrets); + req->con.get.setting_name = g_strdup (setting_name); + req->con.get.hints = g_strdupv ((char **) hints); + req->con.get.flags = flags; + req->con.get.callback = callback; + req->con.get.callback_data = callback_data; - req = connection_request_new_get (connection, - subject, - existing_secrets, - setting_name, - "getting", - flags, - hints, - callback, - callback_data, - other_data2, - other_data3, - get_complete_cb, - self, - get_next_cb, - get_cancel_cb); - parent = (Request *) req; - g_hash_table_insert (priv->requests, GUINT_TO_POINTER (parent->reqid), req); + if (!nm_g_hash_table_add (priv->requests, req)) + g_assert_not_reached (); /* Kick off the request */ - if (!(req->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM)) - request_add_agents (self, parent); - parent->idle_id = g_idle_add (get_start, req); - return parent->reqid; + if (!(req->con.get.flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM)) + request_add_agents (self, req); + req->idle_id = g_idle_add (request_start, req); + return req; } void nm_agent_manager_cancel_secrets (NMAgentManager *self, - guint32 request_id) + NMAgentManagerCallId request_id) { g_return_if_fail (self != NULL); - g_return_if_fail (request_id > 0); + g_return_if_fail (request_id); + g_return_if_fail (request_id->request_type == REQUEST_TYPE_CON_GET); - g_hash_table_remove (NM_AGENT_MANAGER_GET_PRIVATE (self)->requests, - GUINT_TO_POINTER (request_id)); + if (!g_hash_table_remove (NM_AGENT_MANAGER_GET_PRIVATE (self)->requests, + request_id)) + g_return_if_reached (); + + req_complete_cancel (request_id, FALSE); } /*************************************************************/ static void -save_done_cb (NMSecretAgent *agent, - gconstpointer call_id, - GHashTable *secrets, - GError *error, - gpointer user_data) +_con_save_request_done (NMSecretAgent *agent, + NMSecretAgentCallId call_id, + GVariant *secrets, + GError *error, + gpointer user_data) { - Request *parent = user_data; - ConnectionRequest *req = user_data; + NMAgentManager *self; + Request *req = user_data; const char *agent_dbus_owner; - g_return_if_fail (call_id == parent->current_call_id); + g_return_if_fail (call_id == req->current_call_id); + g_return_if_fail (agent == req->current); + g_return_if_fail (req->request_type == REQUEST_TYPE_CON_SAVE); + + self = req->self; + + req->current_call_id = NULL; if (error) { - nm_log_dbg (LOGD_AGENTS, "(%s) agent failed save secrets request %p/%s: (%d) %s", - nm_secret_agent_get_description (agent), - req, parent->detail, - error ? error->code : -1, - (error && error->message) ? error->message : "(unknown)"); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + _LOGD (agent, "save secrets request cancelled: "LOG_REQ_FMT, + LOG_REQ_ARG (req)); + return; + } + + _LOGD (agent, "agent failed save secrets request "LOG_REQ_FMT": %s", + LOG_REQ_ARG (req), error->message); /* Try the next agent */ - request_next_agent (parent); + request_next_agent (req); + maybe_remove_agent_on_error (agent, error); return; } - nm_log_dbg (LOGD_AGENTS, "(%s) agent saved secrets for request %p/%s", - nm_secret_agent_get_description (agent), - req, parent->detail); + _LOGD (agent, "agent saved secrets for request "LOG_REQ_FMT, + LOG_REQ_ARG (req)); agent_dbus_owner = nm_secret_agent_get_dbus_owner (agent); - req_complete_success (parent, NULL, NULL, agent_dbus_owner); + req_complete (req, NULL, NULL, agent_dbus_owner, NULL); } static void -save_next_cb (Request *parent) +_con_save_request_start (Request *req) { - ConnectionRequest *req = (ConnectionRequest *) parent; - - parent->current_call_id = nm_secret_agent_save_secrets (parent->current, - req->connection, - save_done_cb, - req); - if (parent->current_call_id == NULL) { - /* Shouldn't hit this, but handle it anyway */ - g_warn_if_fail (parent->current_call_id != NULL); - request_next_agent (parent); + req->current_call_id = nm_secret_agent_save_secrets (req->current, + req->con.path, + req->con.connection, + _con_save_request_done, + req); + if (!req->current_call_id) { + g_warn_if_reached (); + request_next_agent (req); } } -static void -save_complete_cb (Request *req, - GHashTable *secrets, - const char *agent_dbus_owner, - const char *agent_username, - GError *error, - gpointer user_data) -{ - g_hash_table_remove (NM_AGENT_MANAGER_GET_PRIVATE (user_data)->requests, - GUINT_TO_POINTER (req->reqid)); -} - -guint32 +void nm_agent_manager_save_secrets (NMAgentManager *self, + const char *path, NMConnection *connection, NMAuthSubject *subject) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); - ConnectionRequest *req; - Request *parent; + Request *req; - g_return_val_if_fail (self != NULL, 0); - g_return_val_if_fail (NM_IS_CONNECTION (connection), 0); + g_return_if_fail (self); + g_return_if_fail (path && *path); + g_return_if_fail (NM_IS_CONNECTION (connection)); nm_log_dbg (LOGD_SETTINGS, "Saving secrets for connection %s (%s)", - nm_connection_get_path (connection), + path, nm_connection_get_id (connection)); - req = connection_request_new_other (connection, - subject, - "saving", - save_complete_cb, - self, - save_next_cb); - parent = (Request *) req; - g_hash_table_insert (priv->requests, GUINT_TO_POINTER (parent->reqid), req); + req = request_new (self, + REQUEST_TYPE_CON_SAVE, + nm_connection_get_id (connection), + subject); + req->con.path = g_strdup (path); + req->con.connection = g_object_ref (connection); + if (!nm_g_hash_table_add (priv->requests, req)) + g_assert_not_reached (); /* Kick off the request */ - request_add_agents (self, parent); - parent->idle_id = g_idle_add (request_start, req); - return parent->reqid; + request_add_agents (self, req); + req->idle_id = g_idle_add (request_start, req); } /*************************************************************/ static void -delete_done_cb (NMSecretAgent *agent, - gconstpointer call_id, - GHashTable *secrets, - GError *error, - gpointer user_data) +_con_del_request_done (NMSecretAgent *agent, + NMSecretAgentCallId call_id, + GVariant *secrets, + GError *error, + gpointer user_data) { + NMAgentManager *self; Request *req = user_data; g_return_if_fail (call_id == req->current_call_id); + g_return_if_fail (agent == req->current); + g_return_if_fail (req->request_type == REQUEST_TYPE_CON_DEL); + + self = req->self; + + req->current_call_id = NULL; if (error) { - nm_log_dbg (LOGD_AGENTS, "(%s) agent failed delete secrets request %p/%s: (%d) %s", - nm_secret_agent_get_description (agent), req, req->detail, - error ? error->code : -1, - (error && error->message) ? error->message : "(unknown)"); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + _LOGD (agent, "delete secrets request cancelled: "LOG_REQ_FMT, + LOG_REQ_ARG (req)); + return; + } + + _LOGD (agent, "agent failed delete secrets request "LOG_REQ_FMT": %s", + LOG_REQ_ARG (req), error->message); } else { - nm_log_dbg (LOGD_AGENTS, "(%s) agent deleted secrets for request %p/%s", - nm_secret_agent_get_description (agent), req, req->detail); + _LOGD (agent, "agent deleted secrets for request "LOG_REQ_FMT, + LOG_REQ_ARG (req)); } /* Tell the next agent to delete secrets */ request_next_agent (req); + if (error) + maybe_remove_agent_on_error (agent, error); } static void -delete_next_cb (Request *parent) +_con_del_request_start (Request *req) { - ConnectionRequest *req = (ConnectionRequest *) parent; - - parent->current_call_id = nm_secret_agent_delete_secrets (parent->current, - req->connection, - delete_done_cb, - req); - if (parent->current_call_id == NULL) { - /* Shouldn't hit this, but handle it anyway */ - g_warn_if_fail (parent->current_call_id != NULL); - request_next_agent (parent); + req->current_call_id = nm_secret_agent_delete_secrets (req->current, + req->con.path, + req->con.connection, + _con_del_request_done, + req); + if (!req->current_call_id) { + g_warn_if_reached (); + request_next_agent (req); } } -static void -delete_complete_cb (Request *req, - GHashTable *secrets, - const char *agent_dbus_owner, - const char *agent_username, - GError *error, - gpointer user_data) -{ - g_hash_table_remove (NM_AGENT_MANAGER_GET_PRIVATE (user_data)->requests, - GUINT_TO_POINTER (req->reqid)); -} - -guint32 +void nm_agent_manager_delete_secrets (NMAgentManager *self, + const char *path, NMConnection *connection) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); NMAuthSubject *subject; - ConnectionRequest *req; - Request *parent; + Request *req; - g_return_val_if_fail (self != NULL, 0); - g_return_val_if_fail (NM_IS_CONNECTION (connection), 0); + g_return_if_fail (self != NULL); + g_return_if_fail (path && *path); + g_return_if_fail (NM_IS_CONNECTION (connection)); nm_log_dbg (LOGD_SETTINGS, "Deleting secrets for connection %s (%s)", - nm_connection_get_path (connection), + path, nm_connection_get_id (connection)); subject = nm_auth_subject_new_internal (); - req = connection_request_new_other (connection, - subject, - "deleting", - delete_complete_cb, - self, - delete_next_cb); + req = request_new (self, + REQUEST_TYPE_CON_DEL, + nm_connection_get_id (connection), + subject); + req->con.path = g_strdup (path); + req->con.connection = g_object_ref (connection); g_object_unref (subject); - parent = (Request *) req; - g_hash_table_insert (priv->requests, GUINT_TO_POINTER (parent->reqid), req); + if (!nm_g_hash_table_add (priv->requests, req)) + g_assert_not_reached (); /* Kick off the request */ - request_add_agents (self, parent); - parent->idle_id = g_idle_add (request_start, req); - return parent->reqid; + request_add_agents (self, req); + req->idle_id = g_idle_add (request_start, req); } /*************************************************************/ @@ -1479,23 +1484,10 @@ nm_agent_manager_all_agents_have_capability (NMAgentManager *manager, /*************************************************************/ -static void -name_owner_changed_cb (NMDBusManager *dbus_mgr, - const char *name, - const char *old_owner, - const char *new_owner, - gpointer user_data) -{ - if (old_owner) { - /* The agent quit, so remove it and let interested clients know */ - remove_agent (NM_AGENT_MANAGER (user_data), old_owner); - } -} - static void agent_permissions_changed_done (NMAuthChain *chain, GError *error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, gpointer user_data) { NMAgentManager *self = NM_AGENT_MANAGER (user_data); @@ -1508,12 +1500,10 @@ agent_permissions_changed_done (NMAuthChain *chain, agent = nm_auth_chain_get_data (chain, "agent"); g_assert (agent); - if (error) { - nm_log_dbg (LOGD_AGENTS, "(%s) failed to request updated agent permissions", - nm_secret_agent_get_description (agent)); - } else { - nm_log_dbg (LOGD_AGENTS, "(%s) updated agent permissions", - nm_secret_agent_get_description (agent)); + if (error) + _LOGD (agent, "failed to request updated agent permissions"); + else { + _LOGD (agent, "updated agent permissions"); if (nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED) == NM_AUTH_CALL_RESULT_YES) share_protected = TRUE; @@ -1566,10 +1556,7 @@ nm_agent_manager_init (NMAgentManager *self) NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self); priv->agents = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - priv->requests = g_hash_table_new_full (g_direct_hash, - g_direct_equal, - NULL, - (GDestroyNotify) request_free); + priv->requests = g_hash_table_new (g_direct_hash, g_direct_equal); } static void @@ -1579,20 +1566,16 @@ constructed (GObject *object) G_OBJECT_CLASS (nm_agent_manager_parent_class)->constructed (object); - priv->dbus_mgr = g_object_ref (nm_dbus_manager_get ()); priv->auth_mgr = g_object_ref (nm_auth_manager_get ()); - nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH_AGENT_MANAGER, object); - - g_signal_connect (priv->dbus_mgr, - NM_DBUS_MANAGER_NAME_OWNER_CHANGED, - G_CALLBACK (name_owner_changed_cb), - object); + nm_exported_object_export (NM_EXPORTED_OBJECT (object)); g_signal_connect (priv->auth_mgr, NM_AUTH_MANAGER_SIGNAL_CHANGED, G_CALLBACK (authority_changed_cb), object); + + NM_UTILS_KEEP_ALIVE (object, nm_session_monitor_get (), "NMAgentManager-depends-on-NMSessionMonitor"); } static void @@ -1600,6 +1583,21 @@ dispose (GObject *object) { NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (object); + if (priv->requests) { + GHashTableIter iter; + Request *req; + +cancel_more: + g_hash_table_iter_init (&iter, priv->requests); + if (g_hash_table_iter_next (&iter, (gpointer *) &req, NULL)) { + g_hash_table_iter_remove (&iter); + req_complete_cancel (req, TRUE); + goto cancel_more; + } + g_hash_table_unref (priv->requests); + priv->requests = NULL; + } + g_slist_free_full (priv->chains, (GDestroyNotify) nm_auth_chain_unref); priv->chains = NULL; @@ -1607,10 +1605,6 @@ dispose (GObject *object) g_hash_table_destroy (priv->agents); priv->agents = NULL; } - if (priv->requests) { - g_hash_table_destroy (priv->requests); - priv->requests = NULL; - } if (priv->auth_mgr) { g_signal_handlers_disconnect_by_func (priv->auth_mgr, @@ -1618,13 +1612,8 @@ dispose (GObject *object) object); g_clear_object (&priv->auth_mgr); } - if (priv->dbus_mgr) { - g_signal_handlers_disconnect_by_func (priv->dbus_mgr, - G_CALLBACK (name_owner_changed_cb), - object); - nm_dbus_manager_unregister_object (priv->dbus_mgr, object); - g_clear_object (&priv->dbus_mgr); - } + + nm_exported_object_unexport (NM_EXPORTED_OBJECT (object)); G_OBJECT_CLASS (nm_agent_manager_parent_class)->dispose (object); } @@ -1633,9 +1622,12 @@ static void nm_agent_manager_class_init (NMAgentManagerClass *agent_manager_class) { GObjectClass *object_class = G_OBJECT_CLASS (agent_manager_class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (agent_manager_class); g_type_class_add_private (agent_manager_class, sizeof (NMAgentManagerPrivate)); + exported_object_class->export_path = NM_DBUS_PATH_AGENT_MANAGER; + /* virtual methods */ object_class->constructed = constructed; object_class->dispose = dispose; @@ -1651,10 +1643,10 @@ nm_agent_manager_class_init (NMAgentManagerClass *agent_manager_class) G_TYPE_NONE, 1, G_TYPE_OBJECT); - dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (agent_manager_class), - &dbus_glib_nm_agent_manager_object_info); - - dbus_g_error_domain_register (NM_AGENT_MANAGER_ERROR, - NM_DBUS_INTERFACE_AGENT_MANAGER, - NM_TYPE_AGENT_MANAGER_ERROR); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (agent_manager_class), + NMDBUS_TYPE_AGENT_MANAGER_SKELETON, + "Register", impl_agent_manager_register, + "RegisterWithCapabilities", impl_agent_manager_register_with_capabilities, + "Unregister", impl_agent_manager_unregister, + NULL); } diff --git a/src/settings/nm-agent-manager.h b/src/settings/nm-agent-manager.h index ac29df22..2f505537 100644 --- a/src/settings/nm-agent-manager.h +++ b/src/settings/nm-agent-manager.h @@ -21,11 +21,10 @@ #ifndef __NETWORKMANAGER_AGENT_MANAGER_H__ #define __NETWORKMANAGER_AGENT_MANAGER_H__ -#include -#include #include + +#include "nm-exported-object.h" #include "nm-secret-agent.h" -#include "nm-types.h" #define NM_TYPE_AGENT_MANAGER (nm_agent_manager_get_type ()) #define NM_AGENT_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_AGENT_MANAGER, NMAgentManager)) @@ -34,12 +33,15 @@ #define NM_IS_AGENT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_AGENT_MANAGER)) #define NM_AGENT_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AGENT_MANAGER, NMAgentManagerClass)) +struct _NMAgentManagerCallId; +typedef struct _NMAgentManagerCallId *NMAgentManagerCallId; + struct _NMAgentManager { - GObject parent; + NMExportedObject parent; }; typedef struct { - GObjectClass parent; + NMExportedObjectClass parent; /* Signals */ void (*agent_registered) (NMAgentManager *agent_mgr, NMSecretAgent *agent); @@ -51,39 +53,38 @@ NMAgentManager *nm_agent_manager_get (void); /* If no agent fulfilled the secrets request, agent_dbus_owner will be NULL */ typedef void (*NMAgentSecretsResultFunc) (NMAgentManager *manager, - guint32 call_id, + NMAgentManagerCallId call_id, const char *agent_dbus_owner, const char *agent_uname, gboolean agent_has_modify, const char *setting_name, NMSecretAgentGetSecretsFlags flags, - GHashTable *secrets, + GVariant *secrets, GError *error, - gpointer user_data, - gpointer other_data2, - gpointer other_data3); - -guint32 nm_agent_manager_get_secrets (NMAgentManager *manager, - NMConnection *connection, - NMAuthSubject *subject, - GHashTable *existing_secrets, - const char *setting_name, - NMSecretAgentGetSecretsFlags flags, - const char **hints, - NMAgentSecretsResultFunc callback, - gpointer callback_data, - gpointer other_data2, - gpointer other_data3); + gpointer user_data); + +NMAgentManagerCallId nm_agent_manager_get_secrets (NMAgentManager *manager, + const char *path, + NMConnection *connection, + NMAuthSubject *subject, + GVariant *existing_secrets, + const char *setting_name, + NMSecretAgentGetSecretsFlags flags, + const char **hints, + NMAgentSecretsResultFunc callback, + gpointer callback_data); void nm_agent_manager_cancel_secrets (NMAgentManager *manager, - guint32 request_id); + NMAgentManagerCallId request_id); -guint32 nm_agent_manager_save_secrets (NMAgentManager *manager, - NMConnection *connection, - NMAuthSubject *subject); +void nm_agent_manager_save_secrets (NMAgentManager *manager, + const char *path, + NMConnection *connection, + NMAuthSubject *subject); -guint32 nm_agent_manager_delete_secrets (NMAgentManager *manager, - NMConnection *connection); +void nm_agent_manager_delete_secrets (NMAgentManager *manager, + const char *path, + NMConnection *connection); NMSecretAgent *nm_agent_manager_get_agent_by_user (NMAgentManager *manager, const char *username); diff --git a/src/settings/nm-inotify-helper.c b/src/settings/nm-inotify-helper.c index 3732e77a..681933cd 100644 --- a/src/settings/nm-inotify-helper.c +++ b/src/settings/nm-inotify-helper.c @@ -23,11 +23,11 @@ #include #include #include -#include #include +#include "nm-default.h" #include "nm-inotify-helper.h" -#include "nm-logging.h" +#include "NetworkManagerUtils.h" /* NOTE: this code should be killed once we depend on a new enough glib to * include the patches from https://bugzilla.gnome.org/show_bug.cgi?id=532815 diff --git a/src/settings/nm-inotify-helper.h b/src/settings/nm-inotify-helper.h index 31e6b9ff..b4e2c612 100644 --- a/src/settings/nm-inotify-helper.h +++ b/src/settings/nm-inotify-helper.h @@ -21,10 +21,10 @@ #ifndef __INOTIFY_HELPER_H__ #define __INOTIFY_HELPER_H__ -#include -#include #include +#include "nm-default.h" + /* NOTE: this code should be killed once we depend on a new enough glib to * include the patches from https://bugzilla.gnome.org/show_bug.cgi?id=532815 */ diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c index 69a5cea2..89e84c26 100644 --- a/src/settings/nm-secret-agent.c +++ b/src/settings/nm-secret-agent.c @@ -23,20 +23,36 @@ #include #include -#include -#include -#include - +#include "nm-default.h" #include "nm-dbus-interface.h" #include "nm-secret-agent.h" -#include "nm-dbus-manager.h" -#include "nm-dbus-glib-types.h" -#include "nm-glib-compat.h" -#include "nm-logging.h" +#include "nm-bus-manager.h" #include "nm-auth-subject.h" #include "nm-simple-connection.h" #include "NetworkManagerUtils.h" +#include "nmdbus-secret-agent.h" + +#define _NMLOG_PREFIX_NAME "secret-agent" +#define _NMLOG_DOMAIN LOGD_AGENTS +#define _NMLOG(level, ...) \ + G_STMT_START { \ + if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \ + char __prefix[32]; \ + \ + if ((self)) \ + g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", ""_NMLOG_PREFIX_NAME"", (self)); \ + else \ + g_strlcpy (__prefix, _NMLOG_PREFIX_NAME, sizeof (__prefix)); \ + _nm_log ((level), (_NMLOG_DOMAIN), 0, \ + "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } G_STMT_END + +#define LOG_REQ_FMT "req[%p,%s,%s%s%s%s]" +#define LOG_REQ_ARG(req) (req), (req)->dbus_command, NM_PRINT_FMT_QUOTE_STRING ((req)->path), ((req)->cancellable ? "" : " (cancelled)") + G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT) #define NM_SECRET_AGENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ @@ -48,30 +64,45 @@ typedef struct { NMAuthSubject *subject; char *identifier; char *owner_username; + char *dbus_owner; NMSecretAgentCapabilities capabilities; - guint32 hash; GSList *permissions; - DBusGProxy *proxy; - guint proxy_destroy_id; + NMDBusSecretAgent *proxy; + NMBusManager *bus_mgr; + GDBusConnection *connection; + gboolean connection_is_private; + gulong on_disconnected_id; GHashTable *requests; } NMSecretAgentPrivate; +enum { + DISCONNECTED, + + LAST_SIGNAL +}; +static guint signals[LAST_SIGNAL] = { 0 }; + /*************************************************************/ -typedef struct { +struct _NMSecretAgentCallId { NMSecretAgent *agent; - DBusGProxyCall *call; + GCancellable *cancellable; char *path; + const char *dbus_command; char *setting_name; + gboolean is_get_secrets; NMSecretAgentCallback callback; gpointer callback_data; -} Request; +}; + +typedef struct _NMSecretAgentCallId Request; static Request * -request_new (NMSecretAgent *agent, +request_new (NMSecretAgent *self, + const char *dbus_command, /* this must be a static string. */ const char *path, const char *setting_name, NMSecretAgentCallback callback, @@ -80,24 +111,60 @@ request_new (NMSecretAgent *agent, Request *r; r = g_slice_new0 (Request); - r->agent = agent; + r->agent = self; r->path = g_strdup (path); r->setting_name = g_strdup (setting_name); + r->dbus_command = dbus_command, r->callback = callback; r->callback_data = callback_data; + r->cancellable = g_cancellable_new (); + _LOGt ("request "LOG_REQ_FMT": created", LOG_REQ_ARG (r)); return r; } +#define request_new(self,dbus_command,path,setting_name,callback,callback_data) request_new(self,""dbus_command"",path,setting_name,callback,callback_data) static void request_free (Request *r) { + NMSecretAgent *self = r->agent; + + _LOGt ("request "LOG_REQ_FMT": destroyed", LOG_REQ_ARG (r)); g_free (r->path); g_free (r->setting_name); + if (r->cancellable) + g_object_unref (r->cancellable); g_slice_free (Request, r); } +static gboolean +request_check_return (Request *r) +{ + NMSecretAgentPrivate *priv; + + if (!r->cancellable) + return FALSE; + + g_return_val_if_fail (NM_IS_SECRET_AGENT (r->agent), FALSE); + + priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); + + if (!g_hash_table_remove (priv->requests, r)) + g_return_val_if_reached (FALSE); + + return TRUE; +} + /*************************************************************/ +static char * +_create_description (const char *dbus_owner, const char *identifier, gulong uid) +{ + return g_strdup_printf ("%s/%s/%lu", + dbus_owner, + identifier, + uid); +} + const char * nm_secret_agent_get_description (NMSecretAgent *agent) { @@ -107,10 +174,9 @@ nm_secret_agent_get_description (NMSecretAgent *agent) priv = NM_SECRET_AGENT_GET_PRIVATE (agent); if (!priv->description) { - priv->description = g_strdup_printf ("%s/%s/%lu", - nm_auth_subject_get_unix_process_dbus_sender (priv->subject), - priv->identifier, - nm_auth_subject_get_unix_process_uid (priv->subject)); + priv->description = _create_description (priv->dbus_owner, + priv->identifier, + nm_auth_subject_get_unix_process_uid (priv->subject)); } return priv->description; @@ -121,7 +187,7 @@ nm_secret_agent_get_dbus_owner (NMSecretAgent *agent) { g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL); - return nm_auth_subject_get_unix_process_dbus_sender (NM_SECRET_AGENT_GET_PRIVATE (agent)->subject); + return NM_SECRET_AGENT_GET_PRIVATE (agent)->dbus_owner; } const char * @@ -164,14 +230,6 @@ nm_secret_agent_get_capabilities (NMSecretAgent *agent) return NM_SECRET_AGENT_GET_PRIVATE (agent)->capabilities; } -guint32 -nm_secret_agent_get_hash (NMSecretAgent *agent) -{ - g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), 0); - - return NM_SECRET_AGENT_GET_PRIVATE (agent)->hash; -} - NMAuthSubject * nm_secret_agent_get_subject (NMSecretAgent *agent) { @@ -253,29 +311,29 @@ nm_secret_agent_has_permission (NMSecretAgent *agent, const char *permission) /*************************************************************/ static void -get_callback (DBusGProxy *proxy, - DBusGProxyCall *call, - void *user_data) +get_callback (GObject *proxy, + GAsyncResult *result, + gpointer user_data) { Request *r = user_data; - NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); - GError *error = NULL; - GHashTable *secrets = NULL; - - g_return_if_fail (call == r->call); - - dbus_g_proxy_end_call (proxy, call, &error, - DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, &secrets, - G_TYPE_INVALID); - r->callback (r->agent, r->call, secrets, error, r->callback_data); - if (secrets) - g_hash_table_unref (secrets); - g_clear_error (&error); - g_hash_table_remove (priv->requests, call); + + if (request_check_return (r)) { + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *secrets = NULL; + + nmdbus_secret_agent_call_get_secrets_finish (priv->proxy, &secrets, result, &error); + if (error) + g_dbus_error_strip_remote_error (error); + r->callback (r->agent, r, secrets, error, r->callback_data); + } + + request_free (r); } -gconstpointer +NMSecretAgentCallId nm_secret_agent_get_secrets (NMSecretAgent *self, + const char *path, NMConnection *connection, const char *setting_name, const char **hints, @@ -284,230 +342,388 @@ nm_secret_agent_get_secrets (NMSecretAgent *self, gpointer callback_data) { NMSecretAgentPrivate *priv; + static const char *no_hints[] = { NULL }; GVariant *dict; - GHashTable *hash; Request *r; - g_return_val_if_fail (self != NULL, NULL); - g_return_val_if_fail (connection != NULL, NULL); + g_return_val_if_fail (NM_IS_SECRET_AGENT (self), NULL); + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + g_return_val_if_fail (path && *path, NULL); g_return_val_if_fail (setting_name != NULL, NULL); priv = NM_SECRET_AGENT_GET_PRIVATE (self); g_return_val_if_fail (priv->proxy != NULL, NULL); dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL); - hash = nm_utils_connection_dict_to_hash (dict); - g_variant_unref (dict); /* Mask off the private flags if present */ flags &= ~NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM; flags &= ~NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS; - r = request_new (self, nm_connection_get_path (connection), setting_name, callback, callback_data); - r->call = dbus_g_proxy_begin_call_with_timeout (priv->proxy, - "GetSecrets", - get_callback, - r, - NULL, - 120000, /* 120 seconds */ - DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash, - DBUS_TYPE_G_OBJECT_PATH, nm_connection_get_path (connection), - G_TYPE_STRING, setting_name, - G_TYPE_STRV, hints, - G_TYPE_UINT, flags, - G_TYPE_INVALID); - g_hash_table_insert (priv->requests, r->call, r); - - g_hash_table_destroy (hash); - return r->call; + r = request_new (self, "GetSecrets", path, setting_name, callback, callback_data); + r->is_get_secrets = TRUE; + g_hash_table_add (priv->requests, r); + nmdbus_secret_agent_call_get_secrets (priv->proxy, + dict, + path, + setting_name, + hints ? hints : no_hints, + flags, + r->cancellable, + get_callback, r); + + return r; } +/*************************************************************/ + static void -cancel_done (DBusGProxy *proxy, DBusGProxyCall *call_id, void *user_data) +cancel_done (GObject *proxy, GAsyncResult *result, gpointer user_data) { + char *description = user_data; GError *error = NULL; - if (!dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID)) { - nm_log_dbg (LOGD_AGENTS, "(%s): agent failed to cancel secrets: (%d) %s", - (const char *) user_data, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); + if (!nmdbus_secret_agent_call_cancel_get_secrets_finish (NMDBUS_SECRET_AGENT (proxy), result, &error)) { + nm_log_dbg (LOGD_AGENTS, "%s%s%s: agent failed to cancel secrets: %s", + NM_PRINT_FMT_QUOTED (description, "(", description, ")", "???"), + error->message); g_clear_error (&error); } + + g_free (description); +} + +static void +do_cancel_secrets (NMSecretAgent *self, Request *r, gboolean disposing) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + GCancellable *cancellable; + NMSecretAgentCallback callback; + gpointer callback_data; + + g_return_if_fail (r->agent == self); + g_return_if_fail (r->cancellable); + + if ( r->is_get_secrets + && priv->proxy) { + /* for GetSecrets call, we must cancel the request. */ + nmdbus_secret_agent_call_cancel_get_secrets (priv->proxy, + r->path, r->setting_name, + NULL, + cancel_done, + g_strdup (nm_secret_agent_get_description (self))); + } + + cancellable = r->cancellable; + callback = r->callback; + callback_data = r->callback_data; + + /* During g_cancellable_cancel() the d-bus method might return synchronously. + * Clear r->cancellable first, so that it doesn't actually do anything. + * After that, @r might be already freed. */ + r->cancellable = NULL; + g_cancellable_cancel (cancellable); + g_object_unref (cancellable); + + /* Don't free the request @r. It will be freed when the d-bus call returns. + * Only clear r->cancellable to indicate that the request was cancelled. */ + + if (callback) { + gs_free_error GError *error = NULL; + + nm_utils_error_set_cancelled (&error, disposing, "NMSecretAgent"); + /* @r might be a dangling pointer at this point. However, that is no problem + * to pass it as (opaque) call_id. */ + callback (self, r, NULL, error, callback_data); + } } +/** + * nm_secret_agent_cancel_secrets: + * @self: #NMSecretAgent instance + * @call_id: the call id to cancel + * + * It is an error to pass an invalid @call_id or a @call_id for an operation + * that already completed. NMSecretAgent will always invoke the callback, + * also for cancel() and dispose(). + * In case of nm_secret_agent_cancel_secrets() this will synchronously invoke the + * callback before nm_secret_agent_cancel_secrets() returns. + */ void -nm_secret_agent_cancel_secrets (NMSecretAgent *self, gconstpointer call) +nm_secret_agent_cancel_secrets (NMSecretAgent *self, NMSecretAgentCallId call_id) { NMSecretAgentPrivate *priv; - Request *r; + Request *r = call_id; + + g_return_if_fail (NM_IS_SECRET_AGENT (self)); + g_return_if_fail (r); - g_return_if_fail (self != NULL); priv = NM_SECRET_AGENT_GET_PRIVATE (self); - g_return_if_fail (priv->proxy != NULL); - - r = g_hash_table_lookup (priv->requests, call); - g_return_if_fail (r != NULL); - - dbus_g_proxy_cancel_call (priv->proxy, (gpointer) call); - - dbus_g_proxy_begin_call (priv->proxy, - "CancelGetSecrets", - cancel_done, - g_strdup (nm_secret_agent_get_description (self)), - g_free, - DBUS_TYPE_G_OBJECT_PATH, r->path, - G_TYPE_STRING, r->setting_name, - G_TYPE_INVALID); - g_hash_table_remove (priv->requests, call); + if (!g_hash_table_remove (priv->requests, r)) + g_return_if_reached (); + + do_cancel_secrets (self, r, FALSE); } /*************************************************************/ static void -agent_save_delete_cb (DBusGProxy *proxy, - DBusGProxyCall *call, - void *user_data) +agent_save_cb (GObject *proxy, + GAsyncResult *result, + gpointer user_data) { Request *r = user_data; - NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); - GError *error = NULL; - g_return_if_fail (call == r->call); + if (request_check_return (r)) { + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); + gs_free_error GError *error = NULL; - dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID); - r->callback (r->agent, r->call, NULL, error, r->callback_data); - g_clear_error (&error); - g_hash_table_remove (priv->requests, call); -} + nmdbus_secret_agent_call_save_secrets_finish (priv->proxy, result, &error); + if (error) + g_dbus_error_strip_remote_error (error); + r->callback (r->agent, r, NULL, error, r->callback_data); + } -static gpointer -agent_new_save_delete (NMSecretAgent *self, - NMConnection *connection, - NMConnectionSerializationFlags flags, - const char *method, - NMSecretAgentCallback callback, - gpointer callback_data) -{ - NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); - GVariant *dict; - GHashTable *hash; - Request *r; - const char *cpath = nm_connection_get_path (connection); - - dict = nm_connection_to_dbus (connection, flags); - hash = nm_utils_connection_dict_to_hash (dict); - g_variant_unref (dict); - - r = request_new (self, cpath, NULL, callback, callback_data); - r->call = dbus_g_proxy_begin_call_with_timeout (priv->proxy, - method, - agent_save_delete_cb, - r, - NULL, - 10000, /* 10 seconds */ - DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash, - DBUS_TYPE_G_OBJECT_PATH, cpath, - G_TYPE_INVALID); - g_hash_table_insert (priv->requests, r->call, r); - - g_hash_table_destroy (hash); - return r->call; + request_free (r); } -gconstpointer +NMSecretAgentCallId nm_secret_agent_save_secrets (NMSecretAgent *self, + const char *path, NMConnection *connection, NMSecretAgentCallback callback, gpointer callback_data) { - g_return_val_if_fail (self != NULL, NULL); - g_return_val_if_fail (connection != NULL, NULL); + NMSecretAgentPrivate *priv; + GVariant *dict; + Request *r; + + g_return_val_if_fail (NM_IS_SECRET_AGENT (self), NULL); + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + g_return_val_if_fail (path && *path, NULL); + + priv = NM_SECRET_AGENT_GET_PRIVATE (self); /* Caller should have ensured that only agent-owned secrets exist in 'connection' */ - return agent_new_save_delete (self, - connection, - NM_CONNECTION_SERIALIZE_ALL, - "SaveSecrets", - callback, - callback_data); + dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL); + + r = request_new (self, "SaveSecrets", path, NULL, callback, callback_data); + g_hash_table_add (priv->requests, r); + nmdbus_secret_agent_call_save_secrets (priv->proxy, + dict, + path, + NULL, /* cancelling the request does *not* cancel the D-Bus call. */ + agent_save_cb, r); + + return r; +} + +/*************************************************************/ + +static void +agent_delete_cb (GObject *proxy, + GAsyncResult *result, + gpointer user_data) +{ + Request *r = user_data; + + if (request_check_return (r)) { + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent); + gs_free_error GError *error = NULL; + + nmdbus_secret_agent_call_delete_secrets_finish (priv->proxy, result, &error); + if (error) + g_dbus_error_strip_remote_error (error); + r->callback (r->agent, r, NULL, error, r->callback_data); + } + + request_free (r); } -gconstpointer +NMSecretAgentCallId nm_secret_agent_delete_secrets (NMSecretAgent *self, + const char *path, NMConnection *connection, NMSecretAgentCallback callback, gpointer callback_data) { - g_return_val_if_fail (self != NULL, NULL); - g_return_val_if_fail (connection != NULL, NULL); + NMSecretAgentPrivate *priv; + GVariant *dict; + Request *r; + + g_return_val_if_fail (NM_IS_SECRET_AGENT (self), NULL); + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + g_return_val_if_fail (path && *path, NULL); + + priv = NM_SECRET_AGENT_GET_PRIVATE (self); /* No secrets sent; agents must be smart enough to track secrets using the UUID or something */ - return agent_new_save_delete (self, - connection, - NM_CONNECTION_SERIALIZE_NO_SECRETS, - "DeleteSecrets", - callback, - callback_data); + dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_NO_SECRETS); + + r = request_new (self, "DeleteSecrets", path, NULL, callback, callback_data); + g_hash_table_add (priv->requests, r); + nmdbus_secret_agent_call_delete_secrets (priv->proxy, + dict, + path, + NULL, /* cancelling the request does *not* cancel the D-Bus call. */ + agent_delete_cb, r); + + return r; } +/*************************************************************/ + static void -proxy_cleanup (NMSecretAgent *self) +_on_disconnected_cleanup (NMSecretAgentPrivate *priv) { + if (priv->on_disconnected_id) { + if (priv->connection_is_private) { + g_signal_handler_disconnect (priv->bus_mgr, + priv->on_disconnected_id); + } else { + g_dbus_connection_signal_unsubscribe (priv->connection, + priv->on_disconnected_id); + } + priv->on_disconnected_id = 0; + } + + g_clear_object (&priv->connection); + g_clear_object (&priv->proxy); + g_clear_object (&priv->bus_mgr); +} + +static void +_on_disconnected_private_connection (NMBusManager *mgr, + GDBusConnection *connection, + NMSecretAgent *self) +{ + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + + if (priv->connection != connection) + return; + + _LOGt ("private connection disconnected"); + + _on_disconnected_cleanup (priv); + g_signal_emit (self, signals[DISCONNECTED], 0); +} + +static void +_on_disconnected_name_owner_changed (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + NMSecretAgent *self = NM_SECRET_AGENT (user_data); NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + const char *old_owner, *new_owner; - if (priv->proxy) { - g_signal_handler_disconnect (priv->proxy, priv->proxy_destroy_id); - priv->proxy_destroy_id = 0; - g_clear_object (&priv->proxy); + g_variant_get (parameters, + "(&s&s&s)", + NULL, + &old_owner, + &new_owner); + + _LOGt ("name-owner-changed: %s%s%s => %s%s%s", + NM_PRINT_FMT_QUOTE_STRING (old_owner), + NM_PRINT_FMT_QUOTE_STRING (new_owner)); + + if (!*new_owner) { + _on_disconnected_cleanup (priv); + g_signal_emit (self, signals[DISCONNECTED], 0); } } /*************************************************************/ NMSecretAgent * -nm_secret_agent_new (DBusGMethodInvocation *context, +nm_secret_agent_new (GDBusMethodInvocation *context, NMAuthSubject *subject, const char *identifier, NMSecretAgentCapabilities capabilities) { NMSecretAgent *self; NMSecretAgentPrivate *priv; - char *hash_str, *username; + const char *dbus_owner; struct passwd *pw; + GDBusProxy *proxy; + char *owner_username = NULL; + char *description = NULL; + char buf_subject[64]; + gulong uid; + GDBusConnection *connection; g_return_val_if_fail (context != NULL, NULL); g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); g_return_val_if_fail (nm_auth_subject_is_unix_process (subject), NULL); g_return_val_if_fail (identifier != NULL, NULL); - pw = getpwuid (nm_auth_subject_get_unix_process_uid (subject)); - g_return_val_if_fail (pw != NULL, NULL); - g_return_val_if_fail (pw->pw_name[0] != '\0', NULL); - username = g_strdup (pw->pw_name); + connection = g_dbus_method_invocation_get_connection (context); + + g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL); + + uid = nm_auth_subject_get_unix_process_uid (subject); + + pw = getpwuid (uid); + if (pw && pw->pw_name && pw->pw_name[0]) + owner_username = g_strdup (pw->pw_name); + + dbus_owner = nm_auth_subject_get_unix_process_dbus_sender (subject); self = (NMSecretAgent *) g_object_new (NM_TYPE_SECRET_AGENT, NULL); + priv = NM_SECRET_AGENT_GET_PRIVATE (self); + priv->bus_mgr = g_object_ref (nm_bus_manager_get ()); + priv->connection = g_object_ref (connection); + priv->connection_is_private = !!nm_bus_manager_connection_get_private_name (priv->bus_mgr, connection); + + _LOGt ("constructed: %s, owner=%s%s%s (%s), private-connection=%d, unique-name=%s%s%s", + (description = _create_description (dbus_owner, identifier, uid)), + NM_PRINT_FMT_QUOTE_STRING (owner_username), + nm_auth_subject_to_string (subject, buf_subject, sizeof (buf_subject)), + priv->connection_is_private, + NM_PRINT_FMT_QUOTE_STRING (g_dbus_connection_get_unique_name (priv->connection))); + priv->identifier = g_strdup (identifier); - priv->owner_username = g_strdup (username); + priv->owner_username = owner_username; + priv->dbus_owner = g_strdup (dbus_owner); + priv->description = description; priv->capabilities = capabilities; priv->subject = g_object_ref (subject); - hash_str = g_strdup_printf ("%16lu%s", nm_auth_subject_get_unix_process_uid (subject), identifier); - priv->hash = g_str_hash (hash_str); - g_free (hash_str); - - priv->proxy = nm_dbus_manager_new_proxy (nm_dbus_manager_get (), - context, - nm_auth_subject_get_unix_process_dbus_sender (subject), - NM_DBUS_PATH_SECRET_AGENT, - NM_DBUS_INTERFACE_SECRET_AGENT); - g_assert (priv->proxy); - priv->proxy_destroy_id = g_signal_connect_swapped (priv->proxy, "destroy", - G_CALLBACK (proxy_cleanup), self); + proxy = nm_bus_manager_new_proxy (priv->bus_mgr, + priv->connection, + NMDBUS_TYPE_SECRET_AGENT_PROXY, + priv->dbus_owner, + NM_DBUS_PATH_SECRET_AGENT, + NM_DBUS_INTERFACE_SECRET_AGENT); + g_assert (proxy); + priv->proxy = NMDBUS_SECRET_AGENT (proxy); + + /* we cannot subscribe to notify::g-name-owner because that doesn't work + * for unique names and it doesn't work for private connections. */ + if (priv->connection_is_private) { + priv->on_disconnected_id = g_signal_connect (priv->bus_mgr, + NM_BUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED, + G_CALLBACK (_on_disconnected_private_connection), + self); + } else { + priv->on_disconnected_id = g_dbus_connection_signal_subscribe (priv->connection, + "org.freedesktop.DBus", /* name */ + "org.freedesktop.DBus", /* interface */ + "NameOwnerChanged", /* signal name */ + "/org/freedesktop/DBus", /* path */ + priv->dbus_owner, /* arg0 */ + G_DBUS_SIGNAL_FLAGS_NONE, + _on_disconnected_name_owner_changed, + self, + NULL); + } - g_free (username); return self; } @@ -516,16 +732,25 @@ nm_secret_agent_init (NMSecretAgent *self) { NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); - priv->requests = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, (GDestroyNotify) request_free); + priv->requests = g_hash_table_new (g_direct_hash, g_direct_equal); } static void dispose (GObject *object) { - NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object); + NMSecretAgent *self = NM_SECRET_AGENT (object); + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); + GHashTableIter iter; + Request *r; + + g_hash_table_iter_init (&iter, priv->requests); + while (g_hash_table_iter_next (&iter, (gpointer *) &r, NULL)) { + g_hash_table_iter_remove (&iter); + do_cancel_secrets (self, r, TRUE); + } + + _on_disconnected_cleanup (priv); - proxy_cleanup (NM_SECRET_AGENT (object)); g_clear_object (&priv->subject); G_OBJECT_CLASS (nm_secret_agent_parent_class)->dispose (object); @@ -534,16 +759,20 @@ dispose (GObject *object) static void finalize (GObject *object) { - NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object); + NMSecretAgent *self = NM_SECRET_AGENT (object); + NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self); g_free (priv->description); g_free (priv->identifier); g_free (priv->owner_username); + g_free (priv->dbus_owner); g_slist_free_full (priv->permissions, g_free); g_hash_table_destroy (priv->requests); G_OBJECT_CLASS (nm_secret_agent_parent_class)->finalize (object); + + _LOGt ("finalized"); } static void @@ -556,5 +785,15 @@ nm_secret_agent_class_init (NMSecretAgentClass *config_class) /* virtual methods */ object_class->dispose = dispose; object_class->finalize = finalize; + + /* signals */ + signals[DISCONNECTED] = + g_signal_new (NM_SECRET_AGENT_DISCONNECTED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSecretAgentClass, disconnected), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } diff --git a/src/settings/nm-secret-agent.h b/src/settings/nm-secret-agent.h index f3f4ff89..333aa461 100644 --- a/src/settings/nm-secret-agent.h +++ b/src/settings/nm-secret-agent.h @@ -21,11 +21,8 @@ #ifndef __NETWORKMANAGER_SECRET_AGENT_H__ #define __NETWORKMANAGER_SECRET_AGENT_H__ -#include -#include - #include -#include "nm-types.h" +#include "nm-default.h" #define NM_TYPE_SECRET_AGENT (nm_secret_agent_get_type ()) #define NM_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SECRET_AGENT, NMSecretAgent)) @@ -34,17 +31,23 @@ #define NM_IS_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SECRET_AGENT)) #define NM_SECRET_AGENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SECRET_AGENT, NMSecretAgentClass)) +#define NM_SECRET_AGENT_DISCONNECTED "disconnected" + struct _NMSecretAgent { GObject parent; }; typedef struct { GObjectClass parent; + + void (*disconnected) (NMSecretAgent *self); } NMSecretAgentClass; +typedef struct _NMSecretAgentCallId *NMSecretAgentCallId; + GType nm_secret_agent_get_type (void); -NMSecretAgent *nm_secret_agent_new (DBusGMethodInvocation *context, +NMSecretAgent *nm_secret_agent_new (GDBusMethodInvocation *context, NMAuthSubject *subject, const char *identifier, NMSecretAgentCapabilities capabilities); @@ -63,8 +66,6 @@ gulong nm_secret_agent_get_pid (NMSecretAgent *agent); NMSecretAgentCapabilities nm_secret_agent_get_capabilities (NMSecretAgent *agent); -guint32 nm_secret_agent_get_hash (NMSecretAgent *agent); - NMAuthSubject *nm_secret_agent_get_subject (NMSecretAgent *agent); void nm_secret_agent_add_permission (NMSecretAgent *agent, @@ -75,30 +76,33 @@ gboolean nm_secret_agent_has_permission (NMSecretAgent *agent, const char *permission); typedef void (*NMSecretAgentCallback) (NMSecretAgent *agent, - gconstpointer call, - GHashTable *new_secrets, /* NULL for save & delete */ + NMSecretAgentCallId call_id, + GVariant *new_secrets, /* NULL for save & delete */ GError *error, gpointer user_data); -gconstpointer nm_secret_agent_get_secrets (NMSecretAgent *agent, - NMConnection *connection, - const char *setting_name, - const char **hints, - NMSecretAgentGetSecretsFlags flags, - NMSecretAgentCallback callback, - gpointer callback_data); +NMSecretAgentCallId nm_secret_agent_get_secrets (NMSecretAgent *agent, + const char *path, + NMConnection *connection, + const char *setting_name, + const char **hints, + NMSecretAgentGetSecretsFlags flags, + NMSecretAgentCallback callback, + gpointer callback_data); void nm_secret_agent_cancel_secrets (NMSecretAgent *agent, - gconstpointer call_id); - -gconstpointer nm_secret_agent_save_secrets (NMSecretAgent *agent, - NMConnection *connection, - NMSecretAgentCallback callback, - gpointer callback_data); - -gconstpointer nm_secret_agent_delete_secrets (NMSecretAgent *agent, - NMConnection *connection, - NMSecretAgentCallback callback, - gpointer callback_data); + NMSecretAgentCallId call_id); + +NMSecretAgentCallId nm_secret_agent_save_secrets (NMSecretAgent *agent, + const char *path, + NMConnection *connection, + NMSecretAgentCallback callback, + gpointer callback_data); + +NMSecretAgentCallId nm_secret_agent_delete_secrets (NMSecretAgent *agent, + const char *path, + NMConnection *connection, + NMSecretAgentCallback callback, + gpointer callback_data); #endif /* __NETWORKMANAGER_SECRET_AGENT_H__ */ diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 1fa19237..f7e5002c 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -23,22 +23,18 @@ #include -#include -#include - +#include "nm-default.h" +#include "nm-dbus-interface.h" #include "nm-settings-connection.h" #include "nm-session-monitor.h" -#include "nm-dbus-manager.h" -#include "nm-dbus-glib-types.h" -#include "nm-logging.h" #include "nm-auth-utils.h" #include "nm-auth-subject.h" #include "nm-agent-manager.h" #include "NetworkManagerUtils.h" -#include "nm-properties-changed-signal.h" #include "nm-core-internal.h" -#include "nm-glib-compat.h" -#include "gsystem-local-alloc.h" +#include "nm-audit-manager.h" + +#include "nmdbus-settings-connection.h" #define SETTINGS_TIMESTAMPS_FILE NMSTATEDIR "/timestamps" #define SETTINGS_SEEN_BSSIDS_FILE NMSTATEDIR "/seen-bssids" @@ -52,12 +48,11 @@ if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \ char __prefix[128]; \ const char *__p_prefix = _NMLOG_PREFIX_NAME; \ - const void *const __self = (self); \ \ - if (__self) { \ - const char *__uuid = nm_connection_get_uuid ((NMConnection *) __self); \ + if (self) { \ + const char *__uuid = nm_settings_connection_get_uuid (self); \ \ - g_snprintf (__prefix, sizeof (__prefix), "%s[%p%s%s]", _NMLOG_PREFIX_NAME, __self, __uuid ? "," : "", __uuid ? __uuid : ""); \ + g_snprintf (__prefix, sizeof (__prefix), "%s[%p%s%s]", _NMLOG_PREFIX_NAME, self, __uuid ? "," : "", __uuid ? __uuid : ""); \ __p_prefix = __prefix; \ } \ _nm_log (__level, _NMLOG_DOMAIN, 0, \ @@ -66,36 +61,9 @@ } \ } G_STMT_END - -static void impl_settings_connection_get_settings (NMSettingsConnection *self, - DBusGMethodInvocation *context); - -static void impl_settings_connection_update (NMSettingsConnection *self, - GHashTable *new_settings, - DBusGMethodInvocation *context); - -static void impl_settings_connection_update_unsaved (NMSettingsConnection *self, - GHashTable *new_settings, - DBusGMethodInvocation *context); - -static void impl_settings_connection_save (NMSettingsConnection *self, - DBusGMethodInvocation *context); - -static void impl_settings_connection_delete (NMSettingsConnection *self, - DBusGMethodInvocation *context); - -static void impl_settings_connection_get_secrets (NMSettingsConnection *self, - const gchar *setting_name, - DBusGMethodInvocation *context); - -static void impl_settings_connection_clear_secrets (NMSettingsConnection *self, - DBusGMethodInvocation *context); - -#include "nm-settings-connection-glue.h" - static void nm_settings_connection_connection_interface_init (NMConnectionInterface *iface); -G_DEFINE_TYPE_WITH_CODE (NMSettingsConnection, nm_settings_connection, G_TYPE_OBJECT, +G_DEFINE_TYPE_WITH_CODE (NMSettingsConnection, nm_settings_connection, NM_TYPE_EXPORTED_OBJECT, G_IMPLEMENT_INTERFACE (NM_TYPE_CONNECTION, nm_settings_connection_connection_interface_init) ) @@ -134,7 +102,8 @@ typedef struct { GSList *pending_auths; /* List of pending authentication requests */ gboolean visible; /* Is this connection is visible by some session? */ - GSList *reqs; /* in-progress secrets requests */ + + GSList *get_secret_requests; /* in-progress secrets requests */ /* Caches secrets from on-disk connections; were they not cached any * call to nm_connection_clear_secrets() wipes them out and we'd have @@ -163,91 +132,155 @@ typedef struct { } NMSettingsConnectionPrivate; +/*******************************************************************/ + +gboolean +nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection *self, + NMConnection *applied_connection, + NMSettingCompareFlags compare_flags) +{ + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); + g_return_val_if_fail (NM_IS_CONNECTION (applied_connection), FALSE); + + /* for convenience, we *always* ignore certain settings. */ + compare_flags |= NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS | NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP; + + return nm_connection_compare (NM_CONNECTION (self), applied_connection, compare_flags); +} + /**************************************************************/ -/* Return TRUE to continue, FALSE to stop */ -typedef gboolean (*ForEachSecretFunc) (GHashTableIter *iter, - NMSettingSecretFlags flags, +/* Return TRUE to keep, FALSE to drop */ +typedef gboolean (*ForEachSecretFunc) (NMSettingSecretFlags flags, gpointer user_data); -static void +/* Returns always a non-NULL, non-floating variant that must + * be unrefed by the caller. */ +static GVariant * for_each_secret (NMConnection *self, - GHashTable *secrets, + GVariant *secrets, gboolean remove_non_secrets, ForEachSecretFunc callback, gpointer callback_data) { - GHashTableIter iter; + GVariantBuilder secrets_builder, setting_builder; + GVariantIter secrets_iter, *setting_iter; const char *setting_name; - GHashTable *setting_hash; - /* This function, given a hash of hashes representing new secrets of - * an NMConnection, walks through each toplevel hash (which represents a - * NMSetting), and for each setting, walks through that setting hash's + /* This function, given a dict of dicts representing new secrets of + * an NMConnection, walks through each toplevel dict (which represents a + * NMSetting), and for each setting, walks through that setting dict's * properties. For each property that's a secret, it will check that * secret's flags in the backing NMConnection object, and call a supplied * callback. * * The one complexity is that the VPN setting's 'secrets' property is - * *also* a hash table (since the key/value pairs are arbitrary and known + * *also* a dict (since the key/value pairs are arbitrary and known * only to the VPN plugin itself). That means we have three levels of - * GHashTables that we potentially have to traverse here. When we hit the + * dicts that we potentially have to traverse here. When we hit the * VPN setting's 'secrets' property, we special-case that and iterate over - * each item in that 'secrets' hash table, calling the supplied callback + * each item in that 'secrets' dict, calling the supplied callback * each time. */ - g_return_if_fail (callback); + g_return_val_if_fail (callback, NULL); - /* Walk through the list of setting hashes */ - g_hash_table_iter_init (&iter, secrets); - while (g_hash_table_iter_next (&iter, (gpointer) &setting_name, (gpointer) &setting_hash)) { + g_variant_iter_init (&secrets_iter, secrets); + g_variant_builder_init (&secrets_builder, NM_VARIANT_TYPE_CONNECTION); + while (g_variant_iter_next (&secrets_iter, "{&sa{sv}}", &setting_name, &setting_iter)) { NMSetting *setting; - GHashTableIter secret_iter; const char *secret_name; - GValue *val; + GVariant *val; - if (g_hash_table_size (setting_hash) == 0) - continue; - - /* Get the actual NMSetting from the connection so we can get secret flags - * from the connection data, since flags aren't secrets. What we're - * iterating here is just the secrets, not a whole connection. - */ setting = nm_connection_get_setting_by_name (self, setting_name); - if (setting == NULL) + if (setting == NULL) { + g_variant_iter_free (setting_iter); continue; + } - /* Walk through the list of keys in each setting hash */ - g_hash_table_iter_init (&secret_iter, setting_hash); - while (g_hash_table_iter_next (&secret_iter, (gpointer) &secret_name, (gpointer) &val)) { + g_variant_builder_init (&setting_builder, NM_VARIANT_TYPE_SETTING); + while (g_variant_iter_next (setting_iter, "{&sv}", &secret_name, &val)) { NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; /* VPN secrets need slightly different treatment here since the * "secrets" property is actually a hash table of secrets. */ - if (NM_IS_SETTING_VPN (setting) && (g_strcmp0 (secret_name, NM_SETTING_VPN_SECRETS) == 0)) { - GHashTableIter vpn_secrets_iter; - - /* Iterate through each secret from the VPN hash in the overall secrets hash */ - g_hash_table_iter_init (&vpn_secrets_iter, g_value_get_boxed (val)); - while (g_hash_table_iter_next (&vpn_secrets_iter, (gpointer) &secret_name, NULL)) { - secret_flags = NM_SETTING_SECRET_FLAG_NONE; - nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL); - if (callback (&vpn_secrets_iter, secret_flags, callback_data) == FALSE) - return; + if (NM_IS_SETTING_VPN (setting) && !g_strcmp0 (secret_name, NM_SETTING_VPN_SECRETS)) { + GVariantBuilder vpn_secrets_builder; + GVariantIter vpn_secrets_iter; + const char *vpn_secret_name, *secret; + + /* Iterate through each secret from the VPN dict in the overall secrets dict */ + g_variant_builder_init (&vpn_secrets_builder, G_VARIANT_TYPE ("a{ss}")); + g_variant_iter_init (&vpn_secrets_iter, val); + while (g_variant_iter_next (&vpn_secrets_iter, "{&s&s}", &vpn_secret_name, &secret)) { + if (!nm_setting_get_secret_flags (setting, vpn_secret_name, &secret_flags, NULL)) { + if (!remove_non_secrets) + g_variant_builder_add (&vpn_secrets_builder, "{ss}", vpn_secret_name, secret); + continue; + } + + if (callback (secret_flags, callback_data)) + g_variant_builder_add (&vpn_secrets_builder, "{ss}", vpn_secret_name, secret); } + + g_variant_builder_add (&setting_builder, "{sv}", + secret_name, g_variant_builder_end (&vpn_secrets_builder)); } else { if (!nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL)) { - if (remove_non_secrets) - g_hash_table_iter_remove (&secret_iter); + if (!remove_non_secrets) + g_variant_builder_add (&setting_builder, "{sv}", secret_name, val); continue; } - if (callback (&secret_iter, secret_flags, callback_data) == FALSE) - return; + if (callback (secret_flags, callback_data)) + g_variant_builder_add (&setting_builder, "{sv}", secret_name, val); } + g_variant_unref (val); } + + g_variant_iter_free (setting_iter); + g_variant_builder_add (&secrets_builder, "{sa{sv}}", setting_name, &setting_builder); } + + return g_variant_ref_sink (g_variant_builder_end (&secrets_builder)); +} + +typedef gboolean (*FindSecretFunc) (NMSettingSecretFlags flags, + gpointer user_data); + +typedef struct { + FindSecretFunc find_func; + gpointer find_func_data; + gboolean found; +} FindSecretData; + +static gboolean +find_secret_for_each_func (NMSettingSecretFlags flags, + gpointer user_data) +{ + FindSecretData *data = user_data; + + if (!data->found) + data->found = data->find_func (flags, data->find_func_data); + return FALSE; +} + +static gboolean +find_secret (NMConnection *self, + GVariant *secrets, + FindSecretFunc callback, + gpointer callback_data) +{ + FindSecretData data; + GVariant *dummy; + + data.find_func = callback; + data.find_func_data = callback_data; + data.found = FALSE; + + dummy = for_each_secret (self, secrets, FALSE, find_secret_for_each_func, &data); + g_variant_unref (dummy); + return data.found; } /**************************************************************/ @@ -294,14 +327,18 @@ nm_settings_connection_recheck_visibility (NMSettingsConnection *self) } for (i = 0; i < num; i++) { - const char *puser; + const char *user; + uid_t uid; - if (nm_setting_connection_get_permission (s_con, i, NULL, &puser, NULL)) { - if (nm_session_monitor_user_has_session (priv->session_monitor, puser, NULL, NULL)) { - set_visible (self, TRUE); - return; - } - } + if (!nm_setting_connection_get_permission (s_con, i, NULL, &user, NULL)) + continue; + if (!nm_session_monitor_user_to_uid (user, &uid)) + continue; + if (!nm_session_monitor_session_exists (priv->session_monitor, uid, FALSE)) + continue; + + set_visible (self, TRUE); + return; } set_visible (self, FALSE); @@ -489,11 +526,11 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self, return FALSE; if ( nm_connection_get_path (NM_CONNECTION (self)) - && g_strcmp0 (nm_connection_get_uuid (NM_CONNECTION (self)), nm_connection_get_uuid (new_connection)) != 0) { + && g_strcmp0 (nm_settings_connection_get_uuid (self), nm_connection_get_uuid (new_connection)) != 0) { /* Updating the UUID is not allowed once the path is exported. */ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "connection %s cannot change the UUID from %s to %s", nm_connection_get_id (NM_CONNECTION (self)), - nm_connection_get_uuid (NM_CONNECTION (self)), nm_connection_get_uuid (new_connection)); + "connection %s cannot change the UUID from %s to %s", nm_settings_connection_get_id (self), + nm_settings_connection_get_uuid (self), nm_connection_get_uuid (new_connection)); return FALSE; } @@ -572,9 +609,14 @@ replace_and_commit (NMSettingsConnection *self, gpointer user_data) { GError *error = NULL; + NMSettingsConnectionCommitReason commit_reason = NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION; + + if (g_strcmp0 (nm_connection_get_id (NM_CONNECTION (self)), + nm_connection_get_id (new_connection)) != 0) + commit_reason |= NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED; if (nm_settings_connection_replace_settings (self, new_connection, TRUE, "replace-and-commit-disk", &error)) - nm_settings_connection_commit_changes (self, callback, user_data); + nm_settings_connection_commit_changes (self, commit_reason, callback, user_data); else { g_assert (error); if (callback) @@ -597,6 +639,7 @@ nm_settings_connection_replace_and_commit (NMSettingsConnection *self, static void commit_changes (NMSettingsConnection *self, + NMSettingsConnectionCommitReason commit_reason, NMSettingsConnectionCommitFunc callback, gpointer user_data) { @@ -612,6 +655,7 @@ commit_changes (NMSettingsConnection *self, void nm_settings_connection_commit_changes (NMSettingsConnection *self, + NMSettingsConnectionCommitReason commit_reason, NMSettingsConnectionCommitFunc callback, gpointer user_data) { @@ -619,6 +663,7 @@ nm_settings_connection_commit_changes (NMSettingsConnection *self, if (NM_SETTINGS_CONNECTION_GET_CLASS (self)->commit_changes) { NM_SETTINGS_CONNECTION_GET_CLASS (self)->commit_changes (self, + commit_reason, callback ? callback : ignore_cb, user_data); } else { @@ -672,7 +717,7 @@ remove_entry_from_db (NMSettingsConnection *self, const char* db_name) gsize len; GError *error = NULL; - connection_uuid = nm_connection_get_uuid (NM_CONNECTION (self)); + connection_uuid = nm_settings_connection_get_uuid (self); g_key_file_remove_key (key_file, db_name, connection_uuid, NULL); data = g_key_file_to_data (key_file, &len, &error); @@ -702,7 +747,9 @@ do_delete (NMSettingsConnection *self, /* Tell agents to remove secrets for this connection */ for_agents = nm_simple_connection_new_clone (NM_CONNECTION (self)); nm_connection_clear_secrets (for_agents); - nm_agent_manager_delete_secrets (priv->agent_mgr, for_agents); + nm_agent_manager_delete_secrets (priv->agent_mgr, + nm_connection_get_path (NM_CONNECTION (self)), + for_agents); g_object_unref (for_agents); /* Remove timestamp from timestamps database file */ @@ -720,47 +767,118 @@ do_delete (NMSettingsConnection *self, /**************************************************************/ -static gboolean -supports_secrets (NMSettingsConnection *self, const char *setting_name) + +typedef enum { + GET_SECRETS_INFO_TYPE_REQ, + GET_SECRETS_INFO_TYPE_IDLE, +} GetSecretsInfoType; + +struct _NMSettingsConnectionCallId { + NMSettingsConnection *self; + gboolean had_applied_connection; + NMConnection *applied_connection; + NMSettingsConnectionSecretsFunc callback; + gpointer callback_data; + + GetSecretsInfoType type; + union { + struct { + NMAgentManagerCallId id; + } req; + struct { + guint32 id; + GError *error; + } idle; + } t; +}; + +typedef struct _NMSettingsConnectionCallId GetSecretsInfo; + +static GetSecretsInfo * +_get_secrets_info_new (NMSettingsConnection *self, + NMConnection *applied_connection, + NMSettingsConnectionSecretsFunc callback, + gpointer callback_data) { - /* All secrets supported */ - return TRUE; + GetSecretsInfo *info; + + info = g_slice_new0 (GetSecretsInfo); + + info->self = self; + if (applied_connection) { + info->had_applied_connection = TRUE; + info->applied_connection = applied_connection; + g_object_add_weak_pointer (G_OBJECT (applied_connection), (gpointer *) &info->applied_connection); + } + info->callback = callback; + info->callback_data = callback_data; + + return info; } -static gboolean -clear_nonagent_secrets (GHashTableIter *iter, - NMSettingSecretFlags flags, - gpointer user_data) +static void +_get_secrets_info_callback (GetSecretsInfo *info, + const char *agent_username, + const char *setting_name, + GError *error) { - if (flags != NM_SETTING_SECRET_FLAG_AGENT_OWNED) - g_hash_table_iter_remove (iter); - return TRUE; + if (info->callback) { + info->callback (info->self, + info, + agent_username, + setting_name, + error, + info->callback_data); + } +} + +static void +_get_secrets_info_free (GetSecretsInfo *info) +{ + g_return_if_fail (info && info->self); + + if (info->applied_connection) + g_object_remove_weak_pointer (G_OBJECT (info->applied_connection), (gpointer *) &info->applied_connection); + + if (info->type == GET_SECRETS_INFO_TYPE_IDLE) + g_clear_error (&info->t.idle.error); + + memset (info, 0, sizeof (*info)); + g_slice_free (GetSecretsInfo, info); } static gboolean -clear_unsaved_secrets (GHashTableIter *iter, - NMSettingSecretFlags flags, - gpointer user_data) +supports_secrets (NMSettingsConnection *self, const char *setting_name) { - if (flags & (NM_SETTING_SECRET_FLAG_NOT_SAVED | NM_SETTING_SECRET_FLAG_NOT_REQUIRED)) - g_hash_table_iter_remove (iter); + /* All secrets supported */ return TRUE; } +typedef struct { + NMSettingSecretFlags required; + NMSettingSecretFlags forbidden; +} ForEachSecretFlags; + static gboolean -has_system_owned_secrets (GHashTableIter *iter, - NMSettingSecretFlags flags, - gpointer user_data) +validate_secret_flags (NMSettingSecretFlags flags, + gpointer user_data) { - gboolean *has_system_owned = user_data; + ForEachSecretFlags *cmp_flags = user_data; - if (flags == NM_SETTING_SECRET_FLAG_NONE) { - *has_system_owned = TRUE; + if (!NM_FLAGS_ALL (flags, cmp_flags->required)) + return FALSE; + if (NM_FLAGS_ANY (flags, cmp_flags->forbidden)) return FALSE; - } return TRUE; } +static gboolean +secret_is_system_owned (NMSettingSecretFlags flags, + gpointer user_data) +{ + return !NM_FLAGS_HAS (flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED); +} + static void new_secrets_commit_cb (NMSettingsConnection *self, GError *error, @@ -773,53 +891,33 @@ new_secrets_commit_cb (NMSettingsConnection *self, } static void -agent_secrets_done_cb (NMAgentManager *manager, - guint32 call_id, - const char *agent_dbus_owner, - const char *agent_username, - gboolean agent_has_modify, - const char *setting_name, - NMSecretAgentGetSecretsFlags flags, - GHashTable *secrets, - GError *error, - gpointer user_data, - gpointer other_data2, - gpointer other_data3) +get_cmp_flags (NMSettingsConnection *self, /* only needed for logging */ + GetSecretsInfo *info, /* only needed for logging */ + NMConnection *connection, + const char *agent_dbus_owner, + gboolean agent_has_modify, + const char *setting_name, /* only needed for logging */ + NMSecretAgentGetSecretsFlags flags, + GVariant *secrets, + gboolean *agent_had_system, + ForEachSecretFlags *cmp_flags) { - NMSettingsConnection *self = NM_SETTINGS_CONNECTION (user_data); - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - NMSettingsConnectionSecretsFunc callback = other_data2; - gpointer callback_data = other_data3; - GError *local = NULL; - GVariant *dict; - gboolean agent_had_system = FALSE; + gboolean is_self = (((NMConnection *) self) == connection); - if (error) { - _LOGD ("(%s:%u) secrets request error: (%d) %s", - setting_name, - call_id, - error->code, - error->message ? error->message : "(unknown)"); + g_return_if_fail (secrets); - callback (self, call_id, NULL, setting_name, error, callback_data); - return; - } + cmp_flags->required = NM_SETTING_SECRET_FLAG_NONE; + cmp_flags->forbidden = NM_SETTING_SECRET_FLAG_NONE; - if (!nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name)) { - local = g_error_new (NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND, - "%s.%d - Connection didn't have requested setting '%s'.", - __FILE__, __LINE__, setting_name); - callback (self, call_id, NULL, setting_name, local, callback_data); - g_clear_error (&local); - return; - } + *agent_had_system = FALSE; - g_assert (secrets); if (agent_dbus_owner) { - _LOGD ("(%s:%u) secrets returned from agent %s", - setting_name, - call_id, - agent_dbus_owner); + if (is_self) { + _LOGD ("(%s:%p) secrets returned from agent %s", + setting_name, + info, + agent_dbus_owner); + } /* If the agent returned any system-owned secrets (initial connect and no * secrets given when the connection was created, or something like that) @@ -827,59 +925,145 @@ agent_secrets_done_cb (NMAgentManager *manager, * save those system-owned secrets. If not, discard them and use the * existing secrets, or fail the connection. */ - for_each_secret (NM_CONNECTION (self), secrets, TRUE, has_system_owned_secrets, &agent_had_system); - if (agent_had_system) { + *agent_had_system = find_secret (connection, secrets, secret_is_system_owned, NULL); + if (*agent_had_system) { if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) { /* No user interaction was allowed when requesting secrets; the * agent is being bad. Remove system-owned secrets. */ - _LOGD ("(%s:%u) interaction forbidden but agent %s returned system secrets", - setting_name, - call_id, - agent_dbus_owner); + if (is_self) { + _LOGD ("(%s:%p) interaction forbidden but agent %s returned system secrets", + setting_name, + info, + agent_dbus_owner); + } - for_each_secret (NM_CONNECTION (self), secrets, FALSE, clear_nonagent_secrets, NULL); + cmp_flags->required |= NM_SETTING_SECRET_FLAG_AGENT_OWNED; } else if (agent_has_modify == FALSE) { /* Agent didn't successfully authenticate; clear system-owned secrets * from the secrets the agent returned. */ - _LOGD ("(%s:%u) agent failed to authenticate but provided system secrets", - setting_name, - call_id); + if (is_self) { + _LOGD ("(%s:%p) agent failed to authenticate but provided system secrets", + setting_name, + info); + } - for_each_secret (NM_CONNECTION (self), secrets, FALSE, clear_nonagent_secrets, NULL); + cmp_flags->required |= NM_SETTING_SECRET_FLAG_AGENT_OWNED; } } } else { - _LOGD ("(%s:%u) existing secrets returned", - setting_name, - call_id); + if (is_self) { + _LOGD ("(%s:%p) existing secrets returned", + setting_name, + info); + } } - _LOGD ("(%s:%u) secrets request completed", - setting_name, - call_id); - /* If no user interaction was allowed, make sure that no "unsaved" secrets * came back. Unsaved secrets by definition require user interaction. */ - if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) - for_each_secret (NM_CONNECTION (self), secrets, TRUE, clear_unsaved_secrets, NULL); + if (flags == NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE) { + cmp_flags->forbidden |= ( NM_SETTING_SECRET_FLAG_NOT_SAVED + | NM_SETTING_SECRET_FLAG_NOT_REQUIRED); + } +} + +static void +get_secrets_done_cb (NMAgentManager *manager, + NMAgentManagerCallId call_id_a, + const char *agent_dbus_owner, + const char *agent_username, + gboolean agent_has_modify, + const char *setting_name, + NMSecretAgentGetSecretsFlags flags, + GVariant *secrets, + GError *error, + gpointer user_data) +{ + GetSecretsInfo *info = user_data; + NMSettingsConnection *self; + NMSettingsConnectionPrivate *priv; + NMConnection *applied_connection; + gs_free_error GError *local = NULL; + GVariant *dict; + gboolean agent_had_system = FALSE; + ForEachSecretFlags cmp_flags = { NM_SETTING_SECRET_FLAG_NONE, NM_SETTING_SECRET_FLAG_NONE }; + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = info->self; + g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); + + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + + g_return_if_fail (g_slist_find (priv->get_secret_requests, info)); + + priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info); + + if (error) { + _LOGD ("(%s:%p) secrets request error: %s", + setting_name, info, error->message); + + _get_secrets_info_callback (info, NULL, setting_name, error); + goto out; + } + + if ( info->had_applied_connection + && !info->applied_connection) { + g_set_error_literal (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND, + "Applied connection deleted since requesting secrets"); + _get_secrets_info_callback (info, NULL, setting_name, local); + goto out; + } + + if ( info->had_applied_connection + && !nm_settings_connection_has_unmodified_applied_connection (self, info->applied_connection, NM_SETTING_COMPARE_FLAG_NONE)) { + g_set_error_literal (&local, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "The connection was modified since activation"); + _get_secrets_info_callback (info, NULL, setting_name, local); + goto out; + } + + if (!nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name)) { + g_set_error (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND, + "Connection didn't have requested setting '%s'.", + setting_name); + _get_secrets_info_callback (info, NULL, setting_name, local); + goto out; + } + + get_cmp_flags (self, + info, + NM_CONNECTION (self), + agent_dbus_owner, + agent_has_modify, + setting_name, + flags, + secrets, + &agent_had_system, + &cmp_flags); + + _LOGD ("(%s:%p) secrets request completed", + setting_name, + info); + + dict = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); /* Update the connection with our existing secrets from backing storage */ nm_connection_clear_secrets (NM_CONNECTION (self)); - dict = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); if (!dict || nm_connection_update_secrets (NM_CONNECTION (self), setting_name, dict, &local)) { - GVariant *secrets_dict; + GVariant *filtered_secrets; /* Update the connection with the agent's secrets; by this point if any * system-owned secrets exist in 'secrets' the agent that provided them * will have been authenticated, so those secrets can replace the existing * system secrets. */ - secrets_dict = nm_utils_connection_hash_to_dict (secrets); - if (nm_connection_update_secrets (NM_CONNECTION (self), setting_name, secrets_dict, &local)) { - /* Now that all secrets are updated, copy and cache new secrets, + filtered_secrets = for_each_secret (NM_CONNECTION (self), secrets, TRUE, validate_secret_flags, &cmp_flags); + if (nm_connection_update_secrets (NM_CONNECTION (self), setting_name, filtered_secrets, &local)) { + /* Now that all secrets are updated, copy and cache new secrets, * then save them to backing storage. */ update_system_secrets_cache (self); @@ -891,41 +1075,91 @@ agent_secrets_done_cb (NMAgentManager *manager, * nothing has changed, since agent-owned secrets don't get saved here. */ if (agent_had_system) { - _LOGD ("(%s:%u) saving new secrets to backing storage", + _LOGD ("(%s:%p) saving new secrets to backing storage", setting_name, - call_id); + info); - nm_settings_connection_commit_changes (self, new_secrets_commit_cb, NULL); + nm_settings_connection_commit_changes (self, NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, new_secrets_commit_cb, NULL); } else { - _LOGD ("(%s:%u) new agent secrets processed", + _LOGD ("(%s:%p) new agent secrets processed", setting_name, - call_id); + info); } + } else { - _LOGD ("(%s:%u) failed to update with agent secrets: (%d) %s", + _LOGD ("(%s:%p) failed to update with agent secrets: (%d) %s", setting_name, - call_id, + info, local ? local->code : -1, (local && local->message) ? local->message : "(unknown)"); } - g_variant_unref (secrets_dict); + g_variant_unref (filtered_secrets); } else { - _LOGD ("(%s:%u) failed to update with existing secrets: (%d) %s", + _LOGD ("(%s:%p) failed to update with existing secrets: (%d) %s", setting_name, - call_id, + info, local ? local->code : -1, (local && local->message) ? local->message : "(unknown)"); } - callback (self, call_id, agent_username, setting_name, local, callback_data); + applied_connection = info->applied_connection; + if (applied_connection) { + get_cmp_flags (self, + info, + applied_connection, + agent_dbus_owner, + agent_has_modify, + setting_name, + flags, + secrets, + &agent_had_system, + &cmp_flags); + + nm_connection_clear_secrets (applied_connection); + + if (!dict || nm_connection_update_secrets (applied_connection, setting_name, dict, NULL)) { + GVariant *filtered_secrets; + + filtered_secrets = for_each_secret (applied_connection, secrets, TRUE, validate_secret_flags, &cmp_flags); + nm_connection_update_secrets (applied_connection, setting_name, filtered_secrets, NULL); + g_variant_unref (filtered_secrets); + } + } + + _get_secrets_info_callback (info, agent_username, setting_name, local); g_clear_error (&local); if (dict) g_variant_unref (dict); + +out: + _get_secrets_info_free (info); +} + +static gboolean +get_secrets_idle_cb (GetSecretsInfo *info) +{ + NMSettingsConnectionPrivate *priv; + + g_return_val_if_fail (info && NM_IS_SETTINGS_CONNECTION (info->self), G_SOURCE_REMOVE); + + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (info->self); + + g_return_val_if_fail (g_slist_find (priv->get_secret_requests, info), G_SOURCE_REMOVE); + + priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info); + + _get_secrets_info_callback (info, NULL, NULL, info->t.idle.error); + + _get_secrets_info_free (info); + return G_SOURCE_REMOVE; } /** * nm_settings_connection_get_secrets: * @self: the #NMSettingsConnection + * @applied_connection: (allow-none): if provided, only request secrets + * if @self equals to @applied_connection. Also, update the secrets + * in the @applied_connection. * @subject: the #NMAuthSubject originating the request * @setting_name: the setting to return secrets for * @flags: flags to modify the secrets request @@ -937,86 +1171,140 @@ agent_secrets_done_cb (NMAgentManager *manager, * Retrieves secrets from persistent storage and queries any secret agents for * additional secrets. * - * Returns: a call ID which may be used to cancel the ongoing secrets request + * With the returned call-id, the call can be cancelled. It is an error + * to cancel a call more then once or a call that already completed. + * The callback will always be invoked exactly once, also for cancellation + * and disposing of @self. In those latter cases, the callback will be invoked + * synchronously during cancellation/disposing. + * + * Returns: a call ID which may be used to cancel the ongoing secrets request. **/ -guint32 +NMSettingsConnectionCallId nm_settings_connection_get_secrets (NMSettingsConnection *self, + NMConnection *applied_connection, NMAuthSubject *subject, const char *setting_name, NMSecretAgentGetSecretsFlags flags, const char **hints, NMSettingsConnectionSecretsFunc callback, - gpointer callback_data, - GError **error) + gpointer callback_data) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); GVariant *existing_secrets; - GHashTable *existing_secrets_hash; - guint32 call_id = 0; + NMAgentManagerCallId call_id_a; gs_free char *joined_hints = NULL; + GetSecretsInfo *info; + GError *local = NULL; + + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), NULL); + g_return_val_if_fail ( !applied_connection + || ( NM_IS_CONNECTION (applied_connection) + && (((NMConnection *) self) != applied_connection)), NULL); + + info = _get_secrets_info_new (self, + applied_connection, + callback, + callback_data); + + priv->get_secret_requests = g_slist_append (priv->get_secret_requests, info); /* Use priv->secrets to work around the fact that nm_connection_clear_secrets() * will clear secrets on this object's settings. */ if (!priv->system_secrets) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "%s.%d - Internal error; secrets cache invalid.", - __FILE__, __LINE__); - return 0; + g_set_error_literal (&local, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "secrets cache invalid"); + goto schedule_dummy; } /* Make sure the request actually requests something we can return */ if (!nm_connection_get_setting_by_name (NM_CONNECTION (self), setting_name)) { - g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND, - "%s.%d - Connection didn't have requested setting '%s'.", - __FILE__, __LINE__, setting_name); - return 0; + g_set_error (&local, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_SETTING_NOT_FOUND, + "Connection didn't have requested setting '%s'.", + setting_name); + goto schedule_dummy; + } + + if ( applied_connection + && !nm_settings_connection_has_unmodified_applied_connection (self, applied_connection, NM_SETTING_COMPARE_FLAG_NONE)) { + g_set_error_literal (&local, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "The connection was modified since activation"); + goto schedule_dummy; } existing_secrets = nm_connection_to_dbus (priv->system_secrets, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); - existing_secrets_hash = nm_utils_connection_dict_to_hash (existing_secrets); - call_id = nm_agent_manager_get_secrets (priv->agent_mgr, - NM_CONNECTION (self), - subject, - existing_secrets_hash, - setting_name, - flags, - hints, - agent_secrets_done_cb, - self, - callback, - callback_data); - if (existing_secrets_hash) - g_hash_table_unref (existing_secrets_hash); + if (existing_secrets) + g_variant_ref_sink (existing_secrets); + call_id_a = nm_agent_manager_get_secrets (priv->agent_mgr, + nm_connection_get_path (NM_CONNECTION (self)), + NM_CONNECTION (self), + subject, + existing_secrets, + setting_name, + flags, + hints, + get_secrets_done_cb, + info); + g_assert (call_id_a); if (existing_secrets) g_variant_unref (existing_secrets); - _LOGD ("(%s:%u) secrets requested flags 0x%X hints '%s'", + _LOGD ("(%s:%p) secrets requested flags 0x%X hints '%s'", setting_name, - call_id, + call_id_a, flags, (hints && hints[0]) ? (joined_hints = g_strjoinv (",", (char **) hints)) : "(none)"); - return call_id; + if (call_id_a) { + info->type = GET_SECRETS_INFO_TYPE_REQ; + info->t.req.id = call_id_a; + } else { +schedule_dummy: + info->type = GET_SECRETS_INFO_TYPE_IDLE; + g_propagate_error (&info->t.idle.error, local); + info->t.idle.id = g_idle_add ((GSourceFunc) get_secrets_idle_cb, info); + } + return info; } -void -nm_settings_connection_cancel_secrets (NMSettingsConnection *self, - guint32 call_id) +static void +_get_secrets_cancel (NMSettingsConnection *self, + GetSecretsInfo *info, + gboolean is_disposing) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + gs_free_error GError *error = NULL; + + if (!g_slist_find (priv->get_secret_requests, info)) + g_return_if_reached (); + + priv->get_secret_requests = g_slist_remove (priv->get_secret_requests, info); + + if (info->type == GET_SECRETS_INFO_TYPE_REQ) + nm_agent_manager_cancel_secrets (priv->agent_mgr, info->t.req.id); + else + g_source_remove (info->t.idle.id); - _LOGD ("(%u) secrets canceled", - call_id); + nm_utils_error_set_cancelled (&error, is_disposing, "NMSettingsConnection"); - priv->reqs = g_slist_remove (priv->reqs, GUINT_TO_POINTER (call_id)); - nm_agent_manager_cancel_secrets (priv->agent_mgr, call_id); + _get_secrets_info_callback (info, NULL, NULL, error); + + _get_secrets_info_free (info); +} + +void +nm_settings_connection_cancel_secrets (NMSettingsConnection *self, + NMSettingsConnectionCallId call_id) +{ + _LOGD ("(%p) secrets canceled", call_id); + + _get_secrets_cancel (self, call_id, FALSE); } /**** User authorization **************************************/ typedef void (*AuthCallback) (NMSettingsConnection *self, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, NMAuthSubject *subject, GError *error, gpointer data); @@ -1024,7 +1312,7 @@ typedef void (*AuthCallback) (NMSettingsConnection *self, static void pk_auth_cb (NMAuthChain *chain, GError *chain_error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, gpointer user_data) { NMSettingsConnection *self = NM_SETTINGS_CONNECTION (user_data); @@ -1073,7 +1361,7 @@ pk_auth_cb (NMAuthChain *chain, * Returns: the #NMAuthSubject on success, or %NULL on failure and sets @error */ static NMAuthSubject * -_new_auth_subject (DBusGMethodInvocation *context, GError **error) +_new_auth_subject (GDBusMethodInvocation *context, GError **error) { NMAuthSubject *subject; @@ -1090,7 +1378,7 @@ _new_auth_subject (DBusGMethodInvocation *context, GError **error) static void auth_start (NMSettingsConnection *self, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, NMAuthSubject *subject, const char *check_permission, AuthCallback callback, @@ -1106,7 +1394,6 @@ auth_start (NMSettingsConnection *self, /* Ensure the caller can view this connection */ if (!nm_auth_is_subject_in_acl (NM_CONNECTION (self), - priv->session_monitor, subject, &error_desc)) { error = g_error_new_literal (NM_SETTINGS_ERROR, @@ -1179,16 +1466,15 @@ check_writable (NMConnection *self, GError **error) static void get_settings_auth_cb (NMSettingsConnection *self, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, NMAuthSubject *subject, GError *error, gpointer data) { if (error) - dbus_g_method_return_error (context, error); + g_dbus_method_invocation_return_gerror (context, error); else { GVariant *settings; - GHashTable *settings_hash; NMConnection *dupl_con; NMSettingConnection *s_con; NMSettingWireless *s_wifi; @@ -1226,17 +1512,15 @@ get_settings_auth_cb (NMSettingsConnection *self, */ settings = nm_connection_to_dbus (NM_CONNECTION (dupl_con), NM_CONNECTION_SERIALIZE_NO_SECRETS); g_assert (settings); - settings_hash = nm_utils_connection_dict_to_hash (settings); - dbus_g_method_return (context, settings_hash); - g_hash_table_destroy (settings_hash); - g_variant_unref (settings); + g_dbus_method_invocation_return_value (context, + g_variant_new ("(@a{sa{sv}})", settings)); g_object_unref (dupl_con); } } static void impl_settings_connection_get_settings (NMSettingsConnection *self, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context) { NMAuthSubject *subject; GError *error = NULL; @@ -1245,20 +1529,23 @@ impl_settings_connection_get_settings (NMSettingsConnection *self, if (subject) { auth_start (self, context, subject, NULL, get_settings_auth_cb, NULL); g_object_unref (subject); - } else { - dbus_g_method_return_error (context, error); - g_error_free (error); - } + } else + g_dbus_method_invocation_take_error (context, error); } typedef struct { - DBusGMethodInvocation *context; + GDBusMethodInvocation *context; NMAgentManager *agent_mgr; NMAuthSubject *subject; NMConnection *new_settings; gboolean save_to_disk; } UpdateInfo; +typedef struct { + GDBusMethodInvocation *context; + NMAuthSubject *subject; +} CallbackInfo; + static void has_some_secrets_cb (NMSetting *setting, const char *key, @@ -1319,9 +1606,12 @@ update_complete (NMSettingsConnection *self, GError *error) { if (error) - dbus_g_method_return_error (info->context, error); + g_dbus_method_invocation_return_gerror (info->context, error); else - dbus_g_method_return (info->context); + g_dbus_method_invocation_return_value (info->context, NULL); + + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_UPDATE, self, !error, + info->subject, error ? error->message : NULL); g_clear_object (&info->subject); g_clear_object (&info->agent_mgr); @@ -1347,7 +1637,10 @@ con_update_cb (NMSettingsConnection *self, nm_connection_clear_secrets_with_flags (for_agent, secrets_filter_cb, GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED)); - nm_agent_manager_save_secrets (info->agent_mgr, for_agent, info->subject); + nm_agent_manager_save_secrets (info->agent_mgr, + nm_connection_get_path (NM_CONNECTION (self)), + for_agent, + info->subject); g_object_unref (for_agent); } @@ -1356,7 +1649,7 @@ con_update_cb (NMSettingsConnection *self, static void update_auth_cb (NMSettingsConnection *self, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, NMAuthSubject *subject, GError *error, gpointer data) @@ -1424,8 +1717,8 @@ get_update_modify_permission (NMConnection *old, NMConnection *new) static void impl_settings_connection_update_helper (NMSettingsConnection *self, - GHashTable *new_settings, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, + GVariant *new_settings, gboolean save_to_disk) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); @@ -1447,14 +1740,9 @@ impl_settings_connection_update_helper (NMSettingsConnection *self, /* Check if the settings are valid first */ if (new_settings) { - GVariant *new_settings_dict = nm_utils_connection_hash_to_dict (new_settings); - - tmp = nm_simple_connection_new_from_dbus (new_settings_dict, &error); - g_variant_unref (new_settings_dict); - if (!tmp) { - g_assert (error); + tmp = nm_simple_connection_new_from_dbus (new_settings, &error); + if (!tmp) goto error; - } } subject = _new_auth_subject (context, &error); @@ -1466,7 +1754,6 @@ impl_settings_connection_update_helper (NMSettingsConnection *self, * invisible to yourself. */ if (!nm_auth_is_subject_in_acl (tmp ? tmp : NM_CONNECTION (self), - priv->session_monitor, subject, &error_desc)) { error = g_error_new_literal (NM_SETTINGS_ERROR, @@ -1489,40 +1776,40 @@ impl_settings_connection_update_helper (NMSettingsConnection *self, return; error: + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_UPDATE, self, FALSE, subject, + error->message); + g_clear_object (&tmp); g_clear_object (&subject); - dbus_g_method_return_error (context, error); - g_clear_error (&error); + g_dbus_method_invocation_take_error (context, error); } static void impl_settings_connection_update (NMSettingsConnection *self, - GHashTable *new_settings, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + GVariant *new_settings) { - g_assert (new_settings); - impl_settings_connection_update_helper (self, new_settings, context, TRUE); + impl_settings_connection_update_helper (self, context, new_settings, TRUE); } static void impl_settings_connection_update_unsaved (NMSettingsConnection *self, - GHashTable *new_settings, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + GVariant *new_settings) { - g_assert (new_settings); - impl_settings_connection_update_helper (self, new_settings, context, FALSE); + impl_settings_connection_update_helper (self, context, new_settings, FALSE); } static void impl_settings_connection_save (NMSettingsConnection *self, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context) { /* Do nothing if the connection is already synced with disk */ if (nm_settings_connection_get_unsaved (self)) - impl_settings_connection_update_helper (self, NULL, context, TRUE); + impl_settings_connection_update_helper (self, context, NULL, TRUE); else - dbus_g_method_return (context); + g_dbus_method_invocation_return_value (context, NULL); } static void @@ -1530,27 +1817,39 @@ con_delete_cb (NMSettingsConnection *self, GError *error, gpointer user_data) { - DBusGMethodInvocation *context = user_data; + CallbackInfo *info = user_data; if (error) - dbus_g_method_return_error (context, error); + g_dbus_method_invocation_return_gerror (info->context, error); else - dbus_g_method_return (context); + g_dbus_method_invocation_return_value (info->context, NULL); + + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, self, + !error, info->subject, error ? error->message : NULL); + g_free (info); } static void delete_auth_cb (NMSettingsConnection *self, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, NMAuthSubject *subject, GError *error, gpointer data) { + CallbackInfo *info; + if (error) { - dbus_g_method_return_error (context, error); + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, self, FALSE, subject, + error->message); + g_dbus_method_invocation_return_gerror (context, error); return; } - nm_settings_connection_delete (self, con_delete_cb, context); + info = g_malloc0 (sizeof (*info)); + info->context = context; + info->subject = subject; + + nm_settings_connection_delete (self, con_delete_cb, info); } static const char * @@ -1572,46 +1871,42 @@ get_modify_permission_basic (NMSettingsConnection *self) static void impl_settings_connection_delete (NMSettingsConnection *self, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context) { - NMAuthSubject *subject; + NMAuthSubject *subject = NULL; GError *error = NULL; - - if (!check_writable (NM_CONNECTION (self), &error)) { - dbus_g_method_return_error (context, error); - g_error_free (error); - return; - } + + if (!check_writable (NM_CONNECTION (self), &error)) + goto out_err; subject = _new_auth_subject (context, &error); if (subject) { auth_start (self, context, subject, get_modify_permission_basic (self), delete_auth_cb, NULL); g_object_unref (subject); - } else { - dbus_g_method_return_error (context, error); - g_error_free (error); - } + } else + goto out_err; + + return; +out_err: + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_DELETE, self, FALSE, subject, error->message); + g_dbus_method_invocation_take_error (context, error); } /**************************************************************/ static void dbus_get_agent_secrets_cb (NMSettingsConnection *self, - guint32 call_id, + NMSettingsConnectionCallId call_id, const char *agent_username, const char *setting_name, GError *error, gpointer user_data) { - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - DBusGMethodInvocation *context = user_data; + GDBusMethodInvocation *context = user_data; GVariant *dict; - GHashTable *hash; - - priv->reqs = g_slist_remove (priv->reqs, GUINT_TO_POINTER (call_id)); if (error) - dbus_g_method_return_error (context, error); + g_dbus_method_invocation_return_gerror (context, error); else { /* Return secrets from agent and backing storage to the D-Bus caller; * nm_settings_connection_get_secrets() will have updated itself with @@ -1619,57 +1914,43 @@ dbus_get_agent_secrets_cb (NMSettingsConnection *self, * by the time we get here. */ dict = nm_connection_to_dbus (NM_CONNECTION (self), NM_CONNECTION_SERIALIZE_ONLY_SECRETS); - if (dict) - hash = nm_utils_connection_dict_to_hash (dict); - else - hash = g_hash_table_new (NULL, NULL); - dbus_g_method_return (context, hash); - g_hash_table_destroy (hash); - if (dict) - g_variant_unref (dict); + if (!dict) + dict = g_variant_new_array (G_VARIANT_TYPE ("{sa{sv}}"), NULL, 0); + g_dbus_method_invocation_return_value (context, g_variant_new ("(@a{sa{sv}})", dict)); } } static void -dbus_get_secrets_auth_cb (NMSettingsConnection *self, - DBusGMethodInvocation *context, +dbus_get_secrets_auth_cb (NMSettingsConnection *self, + GDBusMethodInvocation *context, NMAuthSubject *subject, GError *error, gpointer user_data) { - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); char *setting_name = user_data; - guint32 call_id = 0; - GError *local = NULL; if (!error) { - call_id = nm_settings_connection_get_secrets (self, - subject, - setting_name, - NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED - | NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS, - NULL, - dbus_get_agent_secrets_cb, - context, - &local); - if (call_id > 0) { - /* track the request and wait for the callback */ - priv->reqs = g_slist_append (priv->reqs, GUINT_TO_POINTER (call_id)); - } + nm_settings_connection_get_secrets (self, + NULL, + subject, + setting_name, + NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED + | NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS, + NULL, + dbus_get_agent_secrets_cb, + context); } - if (error || local) { - dbus_g_method_return_error (context, error ? error : local); - g_clear_error (&local); - } + if (error) + g_dbus_method_invocation_return_gerror (context, error); g_free (setting_name); } static void impl_settings_connection_get_secrets (NMSettingsConnection *self, - const gchar *setting_name, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + const gchar *setting_name) { NMAuthSubject *subject; GError *error = NULL; @@ -1683,10 +1964,8 @@ impl_settings_connection_get_secrets (NMSettingsConnection *self, dbus_get_secrets_auth_cb, g_strdup (setting_name)); g_object_unref (subject); - } else { - dbus_g_method_return_error (context, error); - g_error_free (error); - } + } else + g_dbus_method_invocation_take_error (context, error); } static void @@ -1694,26 +1973,33 @@ clear_secrets_cb (NMSettingsConnection *self, GError *error, gpointer user_data) { - DBusGMethodInvocation *context = (DBusGMethodInvocation *) user_data; + CallbackInfo *info = user_data; if (error) - dbus_g_method_return_error (context, error); + g_dbus_method_invocation_return_gerror (info->context, error); else - dbus_g_method_return (context); + g_dbus_method_invocation_return_value (info->context, NULL); + + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, self, + !error, info->subject, error ? error->message : NULL); + g_free (info); } static void dbus_clear_secrets_auth_cb (NMSettingsConnection *self, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, NMAuthSubject *subject, GError *error, gpointer user_data) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + CallbackInfo *info; - if (error) - dbus_g_method_return_error (context, error); - else { + if (error) { + g_dbus_method_invocation_return_gerror (context, error); + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, self, + FALSE, subject, error->message); + } else { /* Clear secrets in connection and caches */ nm_connection_clear_secrets (NM_CONNECTION (self)); if (priv->system_secrets) @@ -1722,15 +2008,21 @@ dbus_clear_secrets_auth_cb (NMSettingsConnection *self, nm_connection_clear_secrets (priv->agent_secrets); /* Tell agents to remove secrets for this connection */ - nm_agent_manager_delete_secrets (priv->agent_mgr, NM_CONNECTION (self)); + nm_agent_manager_delete_secrets (priv->agent_mgr, + nm_connection_get_path (NM_CONNECTION (self)), + NM_CONNECTION (self)); - nm_settings_connection_commit_changes (self, clear_secrets_cb, context); + info = g_malloc0 (sizeof (*info)); + info->context = context; + info->subject = subject; + + nm_settings_connection_commit_changes (self, NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, clear_secrets_cb, info); } } static void impl_settings_connection_clear_secrets (NMSettingsConnection *self, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context) { NMAuthSubject *subject; GError *error = NULL; @@ -1745,8 +2037,9 @@ impl_settings_connection_clear_secrets (NMSettingsConnection *self, NULL); g_object_unref (subject); } else { - dbus_g_method_return_error (context, error); - g_error_free (error); + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_CLEAR_SECRETS, self, + FALSE, NULL, error->message); + g_dbus_method_invocation_take_error (context, error); } } @@ -1760,14 +2053,7 @@ nm_settings_connection_signal_remove (NMSettingsConnection *self) if (priv->removed) g_return_if_reached (); priv->removed = TRUE; - - /* Emit removed first */ g_signal_emit_by_name (self, NM_SETTINGS_CONNECTION_REMOVED); - - /* And unregistered last to ensure the removed signal goes out before - * we take the connection off the bus. - */ - nm_dbus_manager_unregister_object (nm_dbus_manager_get (), G_OBJECT (self)); } gboolean @@ -1883,7 +2169,7 @@ nm_settings_connection_update_timestamp (NMSettingsConnection *self, g_clear_error (&error); } - connection_uuid = nm_connection_get_uuid (NM_CONNECTION (self)); + connection_uuid = nm_settings_connection_get_uuid (self); tmp = g_strdup_printf ("%" G_GUINT64_FORMAT, timestamp); g_key_file_set_value (timestamps_file, "timestamps", connection_uuid, tmp); g_free (tmp); @@ -1922,7 +2208,7 @@ nm_settings_connection_read_and_fill_timestamp (NMSettingsConnection *self) /* Get timestamp from database file */ timestamps_file = g_key_file_new (); g_key_file_load_from_file (timestamps_file, SETTINGS_TIMESTAMPS_FILE, G_KEY_FILE_KEEP_COMMENTS, NULL); - connection_uuid = nm_connection_get_uuid (NM_CONNECTION (self)); + connection_uuid = nm_settings_connection_get_uuid (self); tmp_str = g_key_file_get_value (timestamps_file, "timestamps", connection_uuid, &err); if (tmp_str) { timestamp = g_ascii_strtoull (tmp_str, NULL, 10); @@ -2037,7 +2323,7 @@ nm_settings_connection_add_seen_bssid (NMSettingsConnection *self, g_clear_error (&error); } - connection_uuid = nm_connection_get_uuid (NM_CONNECTION (self)); + connection_uuid = nm_settings_connection_get_uuid (self); g_key_file_set_string_list (seen_bssids_file, "seen-bssids", connection_uuid, list, n); g_free (list); @@ -2076,7 +2362,7 @@ nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *self) seen_bssids_file = g_key_file_new (); g_key_file_set_list_separator (seen_bssids_file, ','); if (g_key_file_load_from_file (seen_bssids_file, SETTINGS_SEEN_BSSIDS_FILE, G_KEY_FILE_KEEP_COMMENTS, NULL)) { - connection_uuid = nm_connection_get_uuid (NM_CONNECTION (self)); + connection_uuid = nm_settings_connection_get_uuid (self); tmp_strv = g_key_file_get_string_list (seen_bssids_file, "seen-bssids", connection_uuid, &len, NULL); } g_key_file_free (seen_bssids_file); @@ -2266,6 +2552,18 @@ nm_settings_connection_get_filename (NMSettingsConnection *self) return priv->filename; } +const char * +nm_settings_connection_get_id (NMSettingsConnection *self) +{ + return nm_connection_get_id (NM_CONNECTION (self)); +} + +const char * +nm_settings_connection_get_uuid (NMSettingsConnection *self) +{ + return nm_connection_get_uuid (NM_CONNECTION (self)); +} + /**************************************************************/ static void @@ -2276,11 +2574,8 @@ nm_settings_connection_init (NMSettingsConnection *self) priv->visible = FALSE; priv->ready = TRUE; - priv->session_monitor = nm_session_monitor_get (); - priv->session_changed_id = g_signal_connect (priv->session_monitor, - NM_SESSION_MONITOR_CHANGED, - G_CALLBACK (session_changed_cb), - self); + priv->session_monitor = g_object_ref (nm_session_monitor_get ()); + priv->session_changed_id = nm_session_monitor_connect (priv->session_monitor, session_changed_cb, self); priv->agent_mgr = g_object_ref (nm_agent_manager_get ()); @@ -2308,15 +2603,21 @@ dispose (GObject *object) { NMSettingsConnection *self = NM_SETTINGS_CONNECTION (object); NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - GSList *iter; _LOGD ("disposing"); - if (priv->updated_idle_id) { - g_source_remove (priv->updated_idle_id); - priv->updated_idle_id = 0; + /* Cancel in-progress secrets requests */ + if (priv->agent_mgr) { + while (priv->get_secret_requests) { + GetSecretsInfo *info = priv->get_secret_requests->data; + + _get_secrets_cancel (self, info, TRUE); + g_return_if_fail (!priv->get_secret_requests || (info != priv->get_secret_requests->data)); + } } + nm_clear_g_source (&priv->updated_idle_id); + /* Disconnect handlers. * changed_cb() has to be disconnected *before* nm_connection_clear_secrets(), * because nm_connection_clear_secrets() emits NM_CONNECTION_CHANGED signal. @@ -2332,19 +2633,14 @@ dispose (GObject *object) g_slist_free_full (priv->pending_auths, (GDestroyNotify) nm_auth_chain_unref); priv->pending_auths = NULL; - /* Cancel in-progress secrets requests */ - for (iter = priv->reqs; iter; iter = g_slist_next (iter)) - nm_agent_manager_cancel_secrets (priv->agent_mgr, GPOINTER_TO_UINT (iter->data)); - g_slist_free (priv->reqs); - priv->reqs = NULL; - g_clear_pointer (&priv->seen_bssids, (GDestroyNotify) g_hash_table_destroy); set_visible (self, FALSE); - if (priv->session_changed_id) { - g_signal_handler_disconnect (priv->session_monitor, priv->session_changed_id); + if (priv->session_monitor) { + nm_session_monitor_disconnect (priv->session_monitor, priv->session_changed_id); priv->session_changed_id = 0; + g_clear_object (&priv->session_monitor); } g_clear_object (&priv->agent_mgr); @@ -2408,9 +2704,12 @@ static void nm_settings_connection_class_init (NMSettingsConnectionClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (class); g_type_class_add_private (class, sizeof (NMSettingsConnectionPrivate)); + exported_object_class->export_path = NM_DBUS_PATH_SETTINGS "/%u"; + /* Virtual methods */ object_class->constructed = constructed; object_class->dispose = dispose; @@ -2490,9 +2789,16 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (class), - &dbus_glib_nm_settings_connection_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (class), + NMDBUS_TYPE_SETTINGS_CONNECTION_SKELETON, + "Update", impl_settings_connection_update, + "UpdateUnsaved", impl_settings_connection_update_unsaved, + "Delete", impl_settings_connection_delete, + "GetSettings", impl_settings_connection_get_settings, + "GetSecrets", impl_settings_connection_get_secrets, + "ClearSecrets", impl_settings_connection_clear_secrets, + "Save", impl_settings_connection_save, + NULL); } static void diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h index 512112f0..5c12a8ac 100644 --- a/src/settings/nm-settings-connection.h +++ b/src/settings/nm-settings-connection.h @@ -24,8 +24,9 @@ #include +#include "nm-exported-object.h" #include -#include "nm-types.h" +#include "nm-default.h" G_BEGIN_DECLS @@ -78,6 +79,14 @@ typedef enum NM_SETTINGS_CONNECTION_FLAGS_ALL = ((__NM_SETTINGS_CONNECTION_FLAGS_LAST - 1) << 1) - 1, } NMSettingsConnectionFlags; +typedef enum { /*< skip >*/ + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE = 0, + NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION = (1LL << 0), + NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED = (1LL << 1), +} NMSettingsConnectionCommitReason; + +struct _NMSettingsConnectionCallId; +typedef struct _NMSettingsConnectionCallId *NMSettingsConnectionCallId; typedef struct _NMSettingsConnectionClass NMSettingsConnectionClass; @@ -90,11 +99,11 @@ typedef void (*NMSettingsConnectionDeleteFunc) (NMSettingsConnection *self, gpointer user_data); struct _NMSettingsConnection { - GObject parent; + NMExportedObject parent; }; struct _NMSettingsConnectionClass { - GObjectClass parent; + NMExportedObjectClass parent; /* virtual methods */ void (*replace_and_commit) (NMSettingsConnection *self, @@ -103,6 +112,7 @@ struct _NMSettingsConnectionClass { gpointer user_data); void (*commit_changes) (NMSettingsConnection *self, + NMSettingsConnectionCommitReason commit_reason, NMSettingsConnectionCommitFunc callback, gpointer user_data); @@ -116,7 +126,12 @@ struct _NMSettingsConnectionClass { GType nm_settings_connection_get_type (void); +gboolean nm_settings_connection_has_unmodified_applied_connection (NMSettingsConnection *self, + NMConnection *applied_connection, + NMSettingCompareFlags compare_flage); + void nm_settings_connection_commit_changes (NMSettingsConnection *self, + NMSettingsConnectionCommitReason commit_reason, NMSettingsConnectionCommitFunc callback, gpointer user_data); @@ -136,23 +151,23 @@ void nm_settings_connection_delete (NMSettingsConnection *self, gpointer user_data); typedef void (*NMSettingsConnectionSecretsFunc) (NMSettingsConnection *self, - guint32 call_id, + NMSettingsConnectionCallId call_id, const char *agent_username, const char *setting_name, GError *error, gpointer user_data); -guint32 nm_settings_connection_get_secrets (NMSettingsConnection *self, - NMAuthSubject *subject, - const char *setting_name, - NMSecretAgentGetSecretsFlags flags, - const char **hints, - NMSettingsConnectionSecretsFunc callback, - gpointer callback_data, - GError **error); +NMSettingsConnectionCallId nm_settings_connection_get_secrets (NMSettingsConnection *self, + NMConnection *applied_connection, + NMAuthSubject *subject, + const char *setting_name, + NMSecretAgentGetSecretsFlags flags, + const char **hints, + NMSettingsConnectionSecretsFunc callback, + gpointer callback_data); void nm_settings_connection_cancel_secrets (NMSettingsConnection *self, - guint32 call_id); + NMSettingsConnectionCallId call_id); gboolean nm_settings_connection_is_visible (NMSettingsConnection *self); @@ -212,6 +227,9 @@ void nm_settings_connection_set_filename (NMSettingsConnection *self, const char *filename); const char *nm_settings_connection_get_filename (NMSettingsConnection *self); +const char *nm_settings_connection_get_id (NMSettingsConnection *connection); +const char *nm_settings_connection_get_uuid (NMSettingsConnection *connection); + G_END_DECLS #endif /* __NETWORKMANAGER_SETTINGS_CONNECTION_H__ */ diff --git a/src/settings/nm-settings-plugin.c b/src/settings/nm-settings-plugin.c new file mode 100644 index 00000000..0bce8957 --- /dev/null +++ b/src/settings/nm-settings-plugin.c @@ -0,0 +1,179 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service + * + * 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) 2007 - 2011 Red Hat, Inc. + * Copyright (C) 2008 Novell, Inc. + */ + +#include "config.h" + +#include "nm-settings-plugin.h" +#include "nm-settings-connection.h" + +G_DEFINE_INTERFACE (NMSettingsPlugin, nm_settings_plugin, G_TYPE_OBJECT) + +static void +nm_settings_plugin_default_init (NMSettingsPluginInterface *g_iface) +{ + GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); + static gboolean initialized = FALSE; + + if (initialized) + return; + + /* Properties */ + g_object_interface_install_property + (g_iface, + g_param_spec_string (NM_SETTINGS_PLUGIN_NAME, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_interface_install_property + (g_iface, + g_param_spec_string (NM_SETTINGS_PLUGIN_INFO, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_interface_install_property + (g_iface, + g_param_spec_uint (NM_SETTINGS_PLUGIN_CAPABILITIES, "", "", + NM_SETTINGS_PLUGIN_CAP_NONE, + NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS, + NM_SETTINGS_PLUGIN_CAP_NONE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /* Signals */ + g_signal_new (NM_SETTINGS_PLUGIN_CONNECTION_ADDED, + iface_type, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSettingsPluginInterface, connection_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + NM_TYPE_SETTINGS_CONNECTION); + + g_signal_new (NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED, + iface_type, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSettingsPluginInterface, unmanaged_specs_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + g_signal_new (NM_SETTINGS_PLUGIN_UNRECOGNIZED_SPECS_CHANGED, + iface_type, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMSettingsPluginInterface, unrecognized_specs_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + initialized = TRUE; +} + +void +nm_settings_plugin_init (NMSettingsPlugin *config) +{ + g_return_if_fail (config != NULL); + + if (NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->init) + NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->init (config); +} + +GSList * +nm_settings_plugin_get_connections (NMSettingsPlugin *config) +{ + g_return_val_if_fail (config != NULL, NULL); + + if (NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->get_connections) + return NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->get_connections (config); + return NULL; +} + +gboolean +nm_settings_plugin_load_connection (NMSettingsPlugin *config, + const char *filename) +{ + g_return_val_if_fail (config != NULL, FALSE); + + if (NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->load_connection) + return NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->load_connection (config, filename); + return FALSE; +} + +void +nm_settings_plugin_reload_connections (NMSettingsPlugin *config) +{ + g_return_if_fail (config != NULL); + + if (NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->reload_connections) + NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->reload_connections (config); +} + +GSList * +nm_settings_plugin_get_unmanaged_specs (NMSettingsPlugin *config) +{ + g_return_val_if_fail (config != NULL, NULL); + + if (NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->get_unmanaged_specs) + return NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->get_unmanaged_specs (config); + return NULL; +} + +GSList * +nm_settings_plugin_get_unrecognized_specs (NMSettingsPlugin *config) +{ + g_return_val_if_fail (config != NULL, NULL); + + if (NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->get_unrecognized_specs) + return NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->get_unrecognized_specs (config); + return NULL; +} + +/** + * nm_settings_plugin_add_connection: + * @config: the #NMSettingsPlugin + * @connection: the source connection to create a plugin-specific + * #NMSettingsConnection from + * @save_to_disk: %TRUE to save the connection to disk immediately, %FALSE to + * not save to disk + * @error: on return, a location to store any errors that may occur + * + * Creates a new #NMSettingsConnection for the given source @connection. If the + * plugin cannot handle the given connection type, it should return %NULL and + * set @error. The plugin owns the returned object and the caller must reference + * the object if it wishes to continue using it. + * + * Returns: the new #NMSettingsConnection or %NULL + */ +NMSettingsConnection * +nm_settings_plugin_add_connection (NMSettingsPlugin *config, + NMConnection *connection, + gboolean save_to_disk, + GError **error) +{ + g_return_val_if_fail (config != NULL, NULL); + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + if (NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->add_connection) + return NM_SETTINGS_PLUGIN_GET_INTERFACE (config)->add_connection (config, connection, save_to_disk, error); + + return NULL; +} diff --git a/src/settings/nm-settings-plugin.h b/src/settings/nm-settings-plugin.h new file mode 100644 index 00000000..ab88e7c2 --- /dev/null +++ b/src/settings/nm-settings-plugin.h @@ -0,0 +1,161 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service + * + * 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) 2007 - 2011 Red Hat, Inc. + * Copyright (C) 2008 Novell, Inc. + */ + +#ifndef __NETWORKMANAGER_SETTINGS_PLUGIN_H__ +#define __NETWORKMANAGER_SETTINGS_PLUGIN_H__ + + +#include +#include "nm-default.h" + +G_BEGIN_DECLS + +/* Plugin's factory function that returns a GObject that implements + * NMSettingsPlugin. + */ +GObject * nm_settings_plugin_factory (void); + +#define NM_TYPE_SETTINGS_PLUGIN (nm_settings_plugin_get_type ()) +#define NM_SETTINGS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTINGS_PLUGIN, NMSettingsPlugin)) +#define NM_IS_SETTINGS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTINGS_PLUGIN)) +#define NM_SETTINGS_PLUGIN_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_SETTINGS_PLUGIN, NMSettingsPluginInterface)) + + +#define NM_SETTINGS_PLUGIN_NAME "name" +#define NM_SETTINGS_PLUGIN_INFO "info" +#define NM_SETTINGS_PLUGIN_CAPABILITIES "capabilities" + +#define NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED "unmanaged-specs-changed" +#define NM_SETTINGS_PLUGIN_UNRECOGNIZED_SPECS_CHANGED "unrecognized-specs-changed" +#define NM_SETTINGS_PLUGIN_CONNECTION_ADDED "connection-added" + +typedef enum { + NM_SETTINGS_PLUGIN_CAP_NONE = 0x00000000, + NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS = 0x00000001, + + /* When adding more capabilities, be sure to update the "Capabilities" + * property max value in nm-settings-plugin.c. + */ +} NMSettingsPluginCapabilities; + +typedef enum { + NM_SETTINGS_PLUGIN_PROP_FIRST = 0x1000, + + NM_SETTINGS_PLUGIN_PROP_NAME = NM_SETTINGS_PLUGIN_PROP_FIRST, + NM_SETTINGS_PLUGIN_PROP_INFO, + NM_SETTINGS_PLUGIN_PROP_CAPABILITIES, +} NMSettingsPluginProp; + + +typedef struct _NMSettingsPlugin NMSettingsPlugin; + +typedef struct { + GTypeInterface g_iface; + + /* Called when the plugin is loaded to initialize it */ + void (*init) (NMSettingsPlugin *config); + + /* Returns a GSList of NMSettingsConnection objects that represent + * connections the plugin knows about. The returned list is freed by the + * system settings service. + */ + GSList * (*get_connections) (NMSettingsPlugin *config); + + /* Requests that the plugin load/reload a single connection, if it + * recognizes the filename. Returns success or failure. + */ + gboolean (*load_connection) (NMSettingsPlugin *config, + const char *filename); + + /* Requests that the plugin reload all connection files from disk, + * and emit signals reflecting new, changed, and removed connections. + */ + void (*reload_connections) (NMSettingsPlugin *config); + + /* + * Return a string list of specifications of devices which NetworkManager + * should not manage. Returned list will be freed by the system settings + * service, and each element must be allocated using g_malloc() or its + * variants (g_strdup, g_strdup_printf, etc). + * + * Each string in the list must be in one of the formats recognized by + * nm_device_spec_match_list(). + */ + GSList * (*get_unmanaged_specs) (NMSettingsPlugin *config); + + /* + * Return a string list of specifications of devices for which at least + * one non-NetworkManager-based configuration is defined. Returned list + * will be freed by the system settings service, and each element must be + * allocated using g_malloc() or its variants (g_strdup, g_strdup_printf, + * etc). + * + * Each string in the list must be in one of the formats recognized by + * nm_device_spec_match_list(). + */ + GSList * (*get_unrecognized_specs) (NMSettingsPlugin *config); + + /* + * Initialize the plugin-specific connection and return a new + * NMSettingsConnection subclass that contains the same settings as the + * original connection. The connection should only be saved to backing + * storage if @save_to_disk is TRUE. The returned object is owned by the + * plugin and must be referenced by the owner if necessary. + */ + NMSettingsConnection * (*add_connection) (NMSettingsPlugin *config, + NMConnection *connection, + gboolean save_to_disk, + GError **error); + + /* Signals */ + + /* Emitted when a new connection has been found by the plugin */ + void (*connection_added) (NMSettingsPlugin *config, + NMSettingsConnection *connection); + + /* Emitted when the list of unmanaged device specifications changes */ + void (*unmanaged_specs_changed) (NMSettingsPlugin *config); + + /* Emitted when the list of devices with unrecognized connections changes */ + void (*unrecognized_specs_changed) (NMSettingsPlugin *config); +} NMSettingsPluginInterface; + +GType nm_settings_plugin_get_type (void); + +void nm_settings_plugin_init (NMSettingsPlugin *config); + +GSList *nm_settings_plugin_get_connections (NMSettingsPlugin *config); + +gboolean nm_settings_plugin_load_connection (NMSettingsPlugin *config, + const char *filename); +void nm_settings_plugin_reload_connections (NMSettingsPlugin *config); + +GSList *nm_settings_plugin_get_unmanaged_specs (NMSettingsPlugin *config); +GSList *nm_settings_plugin_get_unrecognized_specs (NMSettingsPlugin *config); + +NMSettingsConnection *nm_settings_plugin_add_connection (NMSettingsPlugin *config, + NMConnection *connection, + gboolean save_to_disk, + GError **error); + +G_END_DECLS + +#endif /* NM_SETTINGS_PLUGIN_H */ diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index f20bc71b..f6f8c374 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -31,10 +31,11 @@ #include #include #include -#include -#include -#include "gsystem-local-alloc.h" +#if HAVE_SELINUX +#include +#endif + #include #include #include @@ -58,12 +59,11 @@ #include "nm-core-internal.h" #include "nm-device-ethernet.h" -#include "nm-dbus-glib-types.h" #include "nm-settings.h" #include "nm-settings-connection.h" -#include "nm-system-config-interface.h" -#include "nm-logging.h" -#include "nm-dbus-manager.h" +#include "nm-settings-plugin.h" +#include "nm-default.h" +#include "nm-bus-manager.h" #include "nm-auth-utils.h" #include "nm-auth-subject.h" #include "nm-session-monitor.h" @@ -71,7 +71,11 @@ #include "nm-agent-manager.h" #include "nm-connection-provider.h" #include "nm-config.h" +#include "nm-audit-manager.h" #include "NetworkManagerUtils.h" +#include "nm-dispatcher.h" + +#include "nmdbus-settings.h" #define LOG(level, ...) \ G_STMT_START { \ @@ -94,52 +98,39 @@ EXPORT(nm_settings_connection_replace_settings) EXPORT(nm_settings_connection_replace_and_commit) /* END LINKER CRACKROCK */ -#define PLUGIN_MODULE_PATH "plugin-module-path" - -static void claim_connection (NMSettings *self, - NMSettingsConnection *connection); - -static gboolean impl_settings_list_connections (NMSettings *self, - GPtrArray **connections, - GError **error); - -static void impl_settings_get_connection_by_uuid (NMSettings *self, - const char *uuid, - DBusGMethodInvocation *context); +#define HOSTNAMED_SERVICE_NAME "org.freedesktop.hostname1" +#define HOSTNAMED_SERVICE_PATH "/org/freedesktop/hostname1" +#define HOSTNAMED_SERVICE_INTERFACE "org.freedesktop.hostname1" -static void impl_settings_add_connection (NMSettings *self, - GHashTable *settings, - DBusGMethodInvocation *context); +#define HOSTNAME_FILE_DEFAULT "/etc/hostname" +#define HOSTNAME_FILE_SUSE "/etc/HOSTNAME" +#define HOSTNAME_FILE_GENTOO "/etc/conf.d/hostname" +#define IFCFG_DIR SYSCONFDIR "/sysconfig/network" +#define CONF_DHCP IFCFG_DIR "/dhcp" -static void impl_settings_add_connection_unsaved (NMSettings *self, - GHashTable *settings, - DBusGMethodInvocation *context); - -static void impl_settings_load_connections (NMSettings *self, - char **filenames, - DBusGMethodInvocation *context); - -static void impl_settings_reload_connections (NMSettings *self, - DBusGMethodInvocation *context); +#define PLUGIN_MODULE_PATH "plugin-module-path" -static void impl_settings_save_hostname (NMSettings *self, - const char *hostname, - DBusGMethodInvocation *context); +#if defined(HOSTNAME_PERSIST_SUSE) +#define HOSTNAME_FILE HOSTNAME_FILE_SUSE +#elif defined(HOSTNAME_PERSIST_GENTOO) +#define HOSTNAME_FILE HOSTNAME_FILE_GENTOO +#else +#define HOSTNAME_FILE HOSTNAME_FILE_DEFAULT +#endif -#include "nm-settings-glue.h" +static void claim_connection (NMSettings *self, + NMSettingsConnection *connection); -static void unmanaged_specs_changed (NMSystemConfigInterface *config, gpointer user_data); -static void unrecognized_specs_changed (NMSystemConfigInterface *config, gpointer user_data); +static void unmanaged_specs_changed (NMSettingsPlugin *config, gpointer user_data); +static void unrecognized_specs_changed (NMSettingsPlugin *config, gpointer user_data); -static void connection_provider_init (NMConnectionProvider *cp_class); +static void connection_provider_iface_init (NMConnectionProviderInterface *cp_iface); -G_DEFINE_TYPE_EXTENDED (NMSettings, nm_settings, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_CONNECTION_PROVIDER, connection_provider_init)) +G_DEFINE_TYPE_EXTENDED (NMSettings, nm_settings, NM_TYPE_EXPORTED_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_CONNECTION_PROVIDER, connection_provider_iface_init)) typedef struct { - NMDBusManager *dbus_mgr; - NMAgentManager *agent_mgr; NMConfig *config; @@ -153,13 +144,23 @@ typedef struct { GSList *unrecognized_specs; GSList *get_connections_cache; + gboolean started; gboolean startup_complete; + + struct { + char *value; + char *file; + GFileMonitor *monitor; + GFileMonitor *dhcp_monitor; + gulong monitor_id; + gulong dhcp_monitor_id; + GDBusProxy *hostnamed_proxy; + } hostname; } NMSettingsPrivate; #define NM_SETTINGS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTINGS, NMSettingsPrivate)) enum { - PROPERTIES_CHANGED, CONNECTION_ADDED, CONNECTION_UPDATED, CONNECTION_UPDATED_BY_USER, @@ -215,7 +216,7 @@ connection_ready_changed (NMSettingsConnection *conn, } static void -plugin_connection_added (NMSystemConfigInterface *config, +plugin_connection_added (NMSettingsPlugin *config, NMSettingsConnection *connection, gpointer user_data) { @@ -229,11 +230,11 @@ load_connections (NMSettings *self) GSList *iter; for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { - NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); + NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data); GSList *plugin_connections; GSList *elt; - plugin_connections = nm_system_config_interface_get_connections (plugin); + plugin_connections = nm_settings_plugin_get_connections (plugin); // FIXME: ensure connections from plugins loaded with a lower priority // get rejected when they conflict with connections from a higher @@ -244,11 +245,11 @@ load_connections (NMSettings *self) g_slist_free (plugin_connections); - g_signal_connect (plugin, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, + g_signal_connect (plugin, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, G_CALLBACK (plugin_connection_added), self); - g_signal_connect (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED, + g_signal_connect (plugin, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED, G_CALLBACK (unmanaged_specs_changed), self); - g_signal_connect (plugin, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED, + g_signal_connect (plugin, NM_SETTINGS_PLUGIN_UNRECOGNIZED_SPECS_CHANGED, G_CALLBACK (unrecognized_specs_changed), self); } @@ -277,20 +278,24 @@ nm_settings_for_each_connection (NMSettings *self, for_each_func (self, NM_SETTINGS_CONNECTION (data), user_data); } -static gboolean +static void impl_settings_list_connections (NMSettings *self, - GPtrArray **connections, - GError **error) + GDBusMethodInvocation *context) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GPtrArray *connections; GHashTableIter iter; gpointer key; - *connections = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1); + connections = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1); g_hash_table_iter_init (&iter, priv->connections); while (g_hash_table_iter_next (&iter, &key, NULL)) - g_ptr_array_add (*connections, g_strdup ((const char *) key)); - return TRUE; + g_ptr_array_add (connections, key); + g_ptr_array_add (connections, NULL); + + g_dbus_method_invocation_return_value (context, + g_variant_new ("(^ao)", connections->pdata)); + g_ptr_array_unref (connections); } NMSettingsConnection * @@ -307,7 +312,7 @@ nm_settings_get_connection_by_uuid (NMSettings *self, const char *uuid) g_hash_table_iter_init (&iter, priv->connections); while (g_hash_table_iter_next (&iter, NULL, (gpointer) &candidate)) { - if (g_strcmp0 (uuid, nm_connection_get_uuid (NM_CONNECTION (candidate))) == 0) + if (g_strcmp0 (uuid, nm_settings_connection_get_uuid (candidate)) == 0) return candidate; } @@ -316,8 +321,8 @@ nm_settings_get_connection_by_uuid (NMSettings *self, const char *uuid) static void impl_settings_get_connection_by_uuid (NMSettings *self, - const char *uuid, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + const char *uuid) { NMSettingsConnection *connection = NULL; NMAuthSubject *subject = NULL; @@ -341,7 +346,6 @@ impl_settings_get_connection_by_uuid (NMSettings *self, } if (!nm_auth_is_subject_in_acl (NM_CONNECTION (connection), - nm_session_monitor_get (), subject, &error_desc)) { error = g_error_new_literal (NM_SETTINGS_ERROR, @@ -352,13 +356,14 @@ impl_settings_get_connection_by_uuid (NMSettings *self, } g_clear_object (&subject); - dbus_g_method_return (context, nm_connection_get_path (NM_CONNECTION (connection))); + g_dbus_method_invocation_return_value ( + context, + g_variant_new ("(o)", nm_connection_get_path (NM_CONNECTION (connection)))); return; error: g_assert (error); - dbus_g_method_return_error (context, error); - g_error_free (error); + g_dbus_method_invocation_take_error (context, error); g_clear_object (&subject); } @@ -424,53 +429,8 @@ nm_settings_get_connection_by_path (NMSettings *self, const char *path) return (NMSettingsConnection *) g_hash_table_lookup (priv->connections, path); } -static char* -uscore_to_wincaps (const char *uscore) -{ - const char *p; - GString *str; - gboolean last_was_uscore; - - last_was_uscore = TRUE; - - str = g_string_new (NULL); - p = uscore; - while (p && *p) { - if (*p == '-' || *p == '_') - last_was_uscore = TRUE; - else { - if (last_was_uscore) { - g_string_append_c (str, g_ascii_toupper (*p)); - last_was_uscore = FALSE; - } else - g_string_append_c (str, *p); - } - ++p; - } - - return g_string_free (str, FALSE); -} - -static void -notify (GObject *object, GParamSpec *pspec) -{ - GValue *value; - GHashTable *hash; - - value = g_slice_new0 (GValue); - hash = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL); - - g_value_init (value, pspec->value_type); - g_object_get_property (object, pspec->name, value); - g_hash_table_insert (hash, uscore_to_wincaps (pspec->name), value); - g_signal_emit (object, signals[PROPERTIES_CHANGED], 0, hash); - g_hash_table_destroy (hash); - g_value_unset (value); - g_slice_free (GValue, value); -} - gboolean -nm_settings_has_connection (NMSettings *self, NMConnection *connection) +nm_settings_has_connection (NMSettings *self, NMSettingsConnection *connection) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GHashTableIter iter; @@ -492,7 +452,7 @@ nm_settings_get_unmanaged_specs (NMSettings *self) return priv->unmanaged_specs; } -static NMSystemConfigInterface * +static NMSettingsPlugin * get_plugin (NMSettings *self, guint32 capability) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); @@ -500,42 +460,109 @@ get_plugin (NMSettings *self, guint32 capability) g_return_val_if_fail (self != NULL, NULL); - /* Do any of the plugins support setting the hostname? */ + /* Do any of the plugins support the given capability? */ for (iter = priv->plugins; iter; iter = iter->next) { - NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; + NMSettingsPluginCapabilities caps = NM_SETTINGS_PLUGIN_CAP_NONE; - g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); + g_object_get (G_OBJECT (iter->data), NM_SETTINGS_PLUGIN_CAPABILITIES, &caps, NULL); if (NM_FLAGS_ALL (caps, capability)) - return NM_SYSTEM_CONFIG_INTERFACE (iter->data); + return NM_SETTINGS_PLUGIN (iter->data); } return NULL; } +#if defined(HOSTNAME_PERSIST_GENTOO) +static gchar * +read_hostname_gentoo (const char *path) +{ + gchar *contents = NULL, *result = NULL, *tmp; + gchar **all_lines = NULL; + guint line_num, i; + + if (!g_file_get_contents (path, &contents, NULL, NULL)) + return NULL; + all_lines = g_strsplit (contents, "\n", 0); + line_num = g_strv_length (all_lines); + for (i = 0; i < line_num; i++) { + g_strstrip (all_lines[i]); + if (all_lines[i][0] == '#' || all_lines[i][0] == '\0') + continue; + if (g_str_has_prefix (all_lines[i], "hostname=")) { + tmp = &all_lines[i][STRLEN ("hostname=")]; + result = g_shell_unquote (tmp, NULL); + break; + } + } + g_strfreev (all_lines); + g_free (contents); + return result; +} +#endif + +#if defined(HOSTNAME_PERSIST_SUSE) +static gboolean +hostname_is_dynamic (void) +{ + GIOChannel *channel; + char *str = NULL; + gboolean dynamic = FALSE; + + channel = g_io_channel_new_file (CONF_DHCP, "r", NULL); + if (!channel) + return dynamic; + + while (g_io_channel_read_line (channel, &str, NULL, NULL, NULL) != G_IO_STATUS_EOF) { + if (str) { + g_strstrip (str); + if (g_str_has_prefix (str, "DHCLIENT_SET_HOSTNAME=")) + dynamic = strcmp (&str[STRLEN ("DHCLIENT_SET_HOSTNAME=")], "\"yes\"") == 0; + g_free (str); + } + } + + g_io_channel_shutdown (channel, FALSE, NULL); + g_io_channel_unref (channel); + + return dynamic; +} +#endif + /* Returns an allocated string which the caller owns and must eventually free */ char * nm_settings_get_hostname (NMSettings *self) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - GSList *iter; char *hostname = NULL; - /* Hostname returned is the hostname returned from the first plugin - * that provides one. - */ - for (iter = priv->plugins; iter; iter = iter->next) { - NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; - - g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); - if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) { - g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, &hostname, NULL); - if (hostname && strlen (hostname)) - return hostname; - g_free (hostname); - } + if (!priv->started) + return NULL; + + if (priv->hostname.hostnamed_proxy) { + hostname = g_strdup (priv->hostname.value); + goto out; } - return NULL; +#if defined(HOSTNAME_PERSIST_GENTOO) + hostname = read_hostname_gentoo (priv->hostname.file); +#else + +#if defined(HOSTNAME_PERSIST_SUSE) + if (priv->hostname.dhcp_monitor_id && hostname_is_dynamic ()) + return NULL; +#endif + if (g_file_get_contents (priv->hostname.file, &hostname, NULL, NULL)) + g_strchomp (hostname); + +#endif /* HOSTNAME_PERSIST_GENTOO */ + +out: + if (hostname && !hostname[0]) { + g_free (hostname); + hostname = NULL; + } + + return hostname; } static gboolean @@ -552,7 +579,7 @@ find_spec (GSList *spec_list, const char *spec) static void update_specs (NMSettings *self, GSList **specs_ptr, - GSList * (*get_specs_func) (NMSystemConfigInterface *)) + GSList * (*get_specs_func) (NMSettingsPlugin *)) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GSList *iter; @@ -563,7 +590,7 @@ update_specs (NMSettings *self, GSList **specs_ptr, for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { GSList *specs, *specs_iter; - specs = get_specs_func (NM_SYSTEM_CONFIG_INTERFACE (iter->data)); + specs = get_specs_func (NM_SETTINGS_PLUGIN (iter->data)); for (specs_iter = specs; specs_iter; specs_iter = specs_iter->next) { if (!find_spec (*specs_ptr, (const char *) specs_iter->data)) { *specs_ptr = g_slist_prepend (*specs_ptr, specs_iter->data); @@ -576,58 +603,52 @@ update_specs (NMSettings *self, GSList **specs_ptr, } static void -unmanaged_specs_changed (NMSystemConfigInterface *config, +unmanaged_specs_changed (NMSettingsPlugin *config, gpointer user_data) { NMSettings *self = NM_SETTINGS (user_data); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); update_specs (self, &priv->unmanaged_specs, - nm_system_config_interface_get_unmanaged_specs); + nm_settings_plugin_get_unmanaged_specs); g_object_notify (G_OBJECT (self), NM_SETTINGS_UNMANAGED_SPECS); } static void -unrecognized_specs_changed (NMSystemConfigInterface *config, +unrecognized_specs_changed (NMSettingsPlugin *config, gpointer user_data) { NMSettings *self = NM_SETTINGS (user_data); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); update_specs (self, &priv->unrecognized_specs, - nm_system_config_interface_get_unrecognized_specs); -} - -static void -hostname_changed (NMSystemConfigInterface *config, - GParamSpec *pspec, - gpointer user_data) -{ - g_object_notify (G_OBJECT (user_data), NM_SETTINGS_HOSTNAME); + nm_settings_plugin_get_unrecognized_specs); } -static void -add_plugin (NMSettings *self, NMSystemConfigInterface *plugin) +static gboolean +add_plugin (NMSettings *self, NMSettingsPlugin *plugin) { NMSettingsPrivate *priv; char *pname = NULL; char *pinfo = NULL; const char *path; - g_return_if_fail (NM_IS_SETTINGS (self)); - g_return_if_fail (NM_IS_SYSTEM_CONFIG_INTERFACE (plugin)); + g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE); + g_return_val_if_fail (NM_IS_SETTINGS_PLUGIN (plugin), FALSE); priv = NM_SETTINGS_GET_PRIVATE (self); - priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin)); - - g_signal_connect (plugin, "notify::hostname", G_CALLBACK (hostname_changed), self); + if (g_slist_find (priv->plugins, plugin)) { + /* don't add duplicates. */ + return FALSE; + } - nm_system_config_interface_init (plugin, NULL); + priv->plugins = g_slist_append (priv->plugins, g_object_ref (plugin)); + nm_settings_plugin_init (plugin); g_object_get (G_OBJECT (plugin), - NM_SYSTEM_CONFIG_INTERFACE_NAME, &pname, - NM_SYSTEM_CONFIG_INTERFACE_INFO, &pinfo, + NM_SETTINGS_PLUGIN_NAME, &pname, + NM_SETTINGS_PLUGIN_INFO, &pinfo, NULL); path = g_object_get_data (G_OBJECT (plugin), PLUGIN_MODULE_PATH); @@ -636,6 +657,8 @@ add_plugin (NMSettings *self, NMSystemConfigInterface *plugin) NM_PRINT_FMT_QUOTED (path, " (", path, ")", "")); g_free (pname); g_free (pinfo); + + return TRUE; } static GObject * @@ -647,11 +670,11 @@ find_plugin (GSList *list, const char *pname) g_return_val_if_fail (pname != NULL, NULL); for (iter = list; iter && !obj; iter = g_slist_next (iter)) { - NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); + NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data); char *list_pname = NULL; g_object_get (G_OBJECT (plugin), - NM_SYSTEM_CONFIG_INTERFACE_NAME, + NM_SETTINGS_PLUGIN_NAME, &list_pname, NULL); if (list_pname && !strcmp (pname, list_pname)) @@ -666,11 +689,12 @@ find_plugin (GSList *list, const char *pname) static void add_keyfile_plugin (NMSettings *self) { - GObject *keyfile_plugin; + gs_unref_object GObject *keyfile_plugin = NULL; keyfile_plugin = nm_settings_keyfile_plugin_new (); g_assert (keyfile_plugin); - add_plugin (self, NM_SYSTEM_CONFIG_INTERFACE (keyfile_plugin)); + if (!add_plugin (self, NM_SETTINGS_PLUGIN (keyfile_plugin))) + g_return_if_reached (); } static gboolean @@ -680,26 +704,34 @@ load_plugins (NMSettings *self, const char **plugins, GError **error) const char **iter; gboolean keyfile_added = FALSE; gboolean success = TRUE; + gboolean add_ibft = FALSE; + gboolean has_no_ibft; + gssize idx_no_ibft, idx_ibft; + + idx_ibft = _nm_utils_strv_find_first ((char **) plugins, -1, "ibft"); + idx_no_ibft = _nm_utils_strv_find_first ((char **) plugins, -1, "no-ibft"); + has_no_ibft = idx_no_ibft >= 0 && idx_no_ibft > idx_ibft; +#if WITH_SETTINGS_PLUGIN_IBFT + add_ibft = idx_no_ibft < 0 && idx_ibft < 0; +#endif for (iter = plugins; iter && *iter; iter++) { - GModule *plugin; - gs_free char *full_name = NULL; - gs_free char *path = NULL; - const char *pname; + const char *pname = *iter; GObject *obj; - GObject * (*factory_func) (void); - struct stat st; - int errsv; - - pname = *iter; if (!*pname || strchr (pname, '/')) { LOG (LOGL_WARN, "ignore invalid plugin \"%s\"", pname); continue; } - obj = find_plugin (list, pname); - if (obj) + if (!strcmp (pname, "ifcfg-suse")) { + LOG (LOGL_WARN, "skipping deprecated plugin ifcfg-suse"); + continue; + } + + if (!strcmp (pname, "no-ibft")) + continue; + if (has_no_ibft && !strcmp (pname, "ibft")) continue; /* keyfile plugin is built-in now */ @@ -711,61 +743,92 @@ load_plugins (NMSettings *self, const char **plugins, GError **error) continue; } - full_name = g_strdup_printf ("nm-settings-plugin-%s", pname); - path = g_module_build_path (NMPLUGINDIR, full_name); - - if (stat (path, &st) != 0) { - errsv = errno; - LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s", pname, path, strerror (errsv)); - continue; - } - if (!S_ISREG (st.st_mode)) { - LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': not a file", pname, path); - continue; - } - if (st.st_uid != 0) { - LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': file must be owned by root", pname, path); - continue; - } - if (st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) { - LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': invalid file permissions", pname, path); + if (_nm_utils_strv_find_first ((char **) plugins, + iter - plugins, + pname) >= 0) { + /* the plugin is already mentioned in the list previously. + * Don't load a duplicate. */ continue; } - plugin = g_module_open (path, G_MODULE_BIND_LOCAL); - if (!plugin) { - LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s", - pname, path, g_module_error ()); + if (find_plugin (list, pname)) continue; - } - /* errors after this point are fatal, because we loaded the shared library already. */ +load_plugin: + { + GModule *plugin; + gs_free char *full_name = NULL; + gs_free char *path = NULL; + GObject * (*factory_func) (void); + struct stat st; + int errsv; + + full_name = g_strdup_printf ("nm-settings-plugin-%s", pname); + path = g_module_build_path (NMPLUGINDIR, full_name); + + if (stat (path, &st) != 0) { + errsv = errno; + LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s", pname, path, strerror (errsv)); + goto next; + } + if (!S_ISREG (st.st_mode)) { + LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': not a file", pname, path); + goto next; + } + if (st.st_uid != 0) { + LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': file must be owned by root", pname, path); + goto next; + } + if (st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) { + LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': invalid file permissions", pname, path); + goto next; + } - if (!g_module_symbol (plugin, "nm_system_config_factory", (gpointer) (&factory_func))) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "Could not find plugin '%s' factory function.", - pname); - success = FALSE; - g_module_close (plugin); - break; - } + plugin = g_module_open (path, G_MODULE_BIND_LOCAL); + if (!plugin) { + LOG (LOGL_WARN, "Could not load plugin '%s' from file '%s': %s", + pname, path, g_module_error ()); + goto next; + } - obj = (*factory_func) (); - if (!obj || !NM_IS_SYSTEM_CONFIG_INTERFACE (obj)) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "Plugin '%s' returned invalid system config object.", - pname); - success = FALSE; - g_module_close (plugin); - break; - } + /* errors after this point are fatal, because we loaded the shared library already. */ - g_module_make_resident (plugin); - g_object_weak_ref (obj, (GWeakNotify) g_module_close, plugin); - g_object_set_data_full (obj, PLUGIN_MODULE_PATH, path, g_free); - path = NULL; - add_plugin (self, NM_SYSTEM_CONFIG_INTERFACE (obj)); - list = g_slist_append (list, obj); + if (!g_module_symbol (plugin, "nm_settings_plugin_factory", (gpointer) (&factory_func))) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "Could not find plugin '%s' factory function.", + pname); + success = FALSE; + g_module_close (plugin); + break; + } + + obj = (*factory_func) (); + if (!obj || !NM_IS_SETTINGS_PLUGIN (obj)) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "Plugin '%s' returned invalid system config object.", + pname); + success = FALSE; + g_module_close (plugin); + break; + } + + g_module_make_resident (plugin); + g_object_weak_ref (obj, (GWeakNotify) g_module_close, plugin); + g_object_set_data_full (obj, PLUGIN_MODULE_PATH, path, g_free); + path = NULL; + if (add_plugin (self, NM_SETTINGS_PLUGIN (obj))) + list = g_slist_append (list, obj); + else + g_object_unref (obj); + } +next: + if (add_ibft && !strcmp (pname, "ifcfg-rh")) { + /* The plugin ibft is not explicitly mentioned but we just enabled "ifcfg-rh". + * Enable "ibft" by default after "ifcfg-rh". */ + pname = "ibft"; + add_ibft = FALSE; + goto load_plugin; + } } /* If keyfile plugin was not among configured plugins, add it as the last one */ @@ -819,7 +882,6 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data) if (!g_hash_table_lookup (priv->connections, cpath)) g_return_if_reached (); - g_object_ref (connection); /* Disconnect signal handlers, as plugins might still keep references @@ -832,6 +894,7 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data) g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_updated_by_user), self); g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_visibility_changed), self); g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_ready_changed), self); + g_object_unref (self); /* Forget about the connection internally */ g_hash_table_remove (priv->connections, (gpointer) cpath); @@ -842,6 +905,8 @@ connection_removed (NMSettingsConnection *connection, gpointer user_data) /* Re-emit for listeners like NMPolicy */ g_signal_emit_by_name (self, NM_CP_SIGNAL_CONNECTION_REMOVED, connection); g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTIONS); + if (nm_exported_object_is_exported (NM_EXPORTED_OBJECT (connection))) + nm_exported_object_unexport (NM_EXPORTED_OBJECT (connection)); check_startup_complete (self); @@ -904,11 +969,10 @@ static void claim_connection (NMSettings *self, NMSettingsConnection *connection) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); - static guint32 ec_counter = 0; GError *error = NULL; GHashTableIter iter; gpointer data; - char *path; + const char *path; NMSettingsConnection *existing; g_return_if_fail (NM_IS_SETTINGS_CONNECTION (connection)); @@ -928,7 +992,7 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) return; } - existing = nm_settings_get_connection_by_uuid (self, nm_connection_get_uuid (NM_CONNECTION (connection))); + existing = nm_settings_get_connection_by_uuid (self, nm_settings_connection_get_uuid (connection)); if (existing) { /* Cannot add duplicate connections per UUID. Just return without action and * log a warning. @@ -941,7 +1005,7 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) * error out. That should not happen unless the admin misconfigured the system * to create conflicting connections. */ nm_log_warn (LOGD_SETTINGS, "plugin provided duplicate connection with UUID %s", - nm_connection_get_uuid (NM_CONNECTION (connection))); + nm_settings_connection_get_uuid (connection)); return; } @@ -957,6 +1021,7 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) /* Evil openconnect migration hack */ openconnect_migrate_hack (NM_CONNECTION (connection)); + g_object_ref (self); g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED, G_CALLBACK (connection_removed), self); g_signal_connect (connection, NM_SETTINGS_CONNECTION_UPDATED, @@ -974,10 +1039,8 @@ claim_connection (NMSettings *self, NMSettingsConnection *connection) /* Export the connection over D-Bus */ g_warn_if_fail (nm_connection_get_path (NM_CONNECTION (connection)) == NULL); - path = g_strdup_printf ("%s/%u", NM_DBUS_PATH_SETTINGS, ec_counter++); + path = nm_exported_object_export (NM_EXPORTED_OBJECT (connection)); nm_connection_set_path (NM_CONNECTION (connection), path); - nm_dbus_manager_register_object (priv->dbus_mgr, path, G_OBJECT (connection)); - g_free (path); g_hash_table_insert (priv->connections, (gpointer) nm_connection_get_path (NM_CONNECTION (connection)), @@ -1047,10 +1110,10 @@ nm_settings_add_connection (NMSettings *self, * contain the same data as the connection it already knows about */ for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { - NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); + NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data); GError *add_error = NULL; - added = nm_system_config_interface_add_connection (plugin, connection, save_to_disk, &add_error); + added = nm_settings_plugin_add_connection (plugin, connection, save_to_disk, &add_error); if (added) { claim_connection (self, added); return added; @@ -1112,21 +1175,24 @@ send_agent_owned_secrets (NMSettings *self, nm_connection_clear_secrets_with_flags (for_agent, secrets_filter_cb, GUINT_TO_POINTER (NM_SETTING_SECRET_FLAG_AGENT_OWNED)); - nm_agent_manager_save_secrets (priv->agent_mgr, for_agent, subject); + nm_agent_manager_save_secrets (priv->agent_mgr, + nm_connection_get_path (NM_CONNECTION (connection)), + for_agent, + subject); g_object_unref (for_agent); } static void pk_add_cb (NMAuthChain *chain, GError *chain_error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, gpointer user_data) { NMSettings *self = NM_SETTINGS (user_data); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); NMAuthCallResult result; GError *error = NULL; - NMConnection *connection; + NMConnection *connection = NULL; NMSettingsConnection *added = NULL; NMSettingsAddCallback callback; gpointer callback_data; @@ -1163,10 +1229,10 @@ pk_add_cb (NMAuthChain *chain, callback_data = nm_auth_chain_get_data (chain, "callback-data"); subject = nm_auth_chain_get_data (chain, "subject"); - callback (self, added, error, context, callback_data); + callback (self, added, error, context, subject, callback_data); /* Send agent-owned secrets to the agents */ - if (!error && added) + if (!error && added && nm_settings_has_connection (self, added)) send_agent_owned_secrets (self, added, subject); g_clear_error (&error); @@ -1207,11 +1273,11 @@ is_adhoc_wpa (NMConnection *connection) void nm_settings_add_connection_dbus (NMSettings *self, - NMConnection *connection, - gboolean save_to_disk, - DBusGMethodInvocation *context, - NMSettingsAddCallback callback, - gpointer user_data) + NMConnection *connection, + gboolean save_to_disk, + GDBusMethodInvocation *context, + NMSettingsAddCallback callback, + gpointer user_data) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); NMSettingConnection *s_con; @@ -1246,7 +1312,7 @@ nm_settings_add_connection_dbus (NMSettings *self, } /* Do any of the plugins support adding? */ - if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)) { + if (!get_plugin (self, NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS)) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_NOT_SUPPORTED, "None of the registered plugins support add."); @@ -1265,7 +1331,6 @@ nm_settings_add_connection_dbus (NMSettings *self, * or that the permissions is empty (ie, visible by everyone). */ if (!nm_auth_is_subject_in_acl (connection, - nm_session_monitor_get (), subject, &error_desc)) { error = g_error_new_literal (NM_SETTINGS_ERROR, @@ -1306,7 +1371,7 @@ nm_settings_add_connection_dbus (NMSettings *self, done: if (error) - callback (self, NULL, error, context, user_data); + callback (self, NULL, error, context, subject, user_data); g_clear_error (&error); g_clear_object (&subject); @@ -1316,29 +1381,37 @@ static void impl_settings_add_connection_add_cb (NMSettings *self, NMSettingsConnection *connection, GError *error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, + NMAuthSubject *subject, gpointer user_data) { - if (error) - dbus_g_method_return_error (context, error); - else - dbus_g_method_return (context, nm_connection_get_path (NM_CONNECTION (connection))); + if (error) { + g_dbus_method_invocation_return_gerror (context, error); + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, NULL, FALSE, subject, error->message); + } else { + g_dbus_method_invocation_return_value ( + context, + g_variant_new ("(o)", nm_connection_get_path (NM_CONNECTION (connection)))); + nm_audit_log_connection_op (NM_AUDIT_OP_CONN_ADD, connection, TRUE, + subject, NULL); + } } static void impl_settings_add_connection_helper (NMSettings *self, - GHashTable *settings, - gboolean save_to_disk, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + GVariant *settings, + gboolean save_to_disk) { NMConnection *connection; - GVariant *dict; GError *error = NULL; - dict = nm_utils_connection_hash_to_dict (settings); - connection = nm_simple_connection_new_from_dbus (dict, &error); - g_variant_unref (dict); + connection = nm_simple_connection_new_from_dbus (settings, &error); + if (connection) { + if (!nm_connection_verify_secrets (connection, &error)) + goto failure; + nm_settings_add_connection_dbus (self, connection, save_to_disk, @@ -1346,50 +1419,49 @@ impl_settings_add_connection_helper (NMSettings *self, impl_settings_add_connection_add_cb, NULL); g_object_unref (connection); - } else { - g_assert (error); - dbus_g_method_return_error (context, error); - g_error_free (error); + return; } + +failure: + g_assert (error); + g_dbus_method_invocation_take_error (context, error); } static void impl_settings_add_connection (NMSettings *self, - GHashTable *settings, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + GVariant *settings) { - impl_settings_add_connection_helper (self, settings, TRUE, context); + impl_settings_add_connection_helper (self, context, settings, TRUE); } static void impl_settings_add_connection_unsaved (NMSettings *self, - GHashTable *settings, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + GVariant *settings) { - impl_settings_add_connection_helper (self, settings, FALSE, context); + impl_settings_add_connection_helper (self, context, settings, FALSE); } static gboolean -ensure_root (NMDBusManager *dbus_mgr, - DBusGMethodInvocation *context) +ensure_root (NMBusManager *dbus_mgr, + GDBusMethodInvocation *context) { gulong caller_uid; GError *error = NULL; - if (!nm_dbus_manager_get_caller_info (dbus_mgr, context, NULL, &caller_uid, NULL)) { + if (!nm_bus_manager_get_caller_info (dbus_mgr, context, NULL, &caller_uid, NULL)) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, "Unable to determine request UID."); - dbus_g_method_return_error (context, error); - g_error_free (error); + g_dbus_method_invocation_take_error (context, error); return FALSE; } if (caller_uid != 0) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED, "Permission denied"); - dbus_g_method_return_error (context, error); - g_error_free (error); + g_dbus_method_invocation_take_error (context, error); return FALSE; } @@ -1398,24 +1470,24 @@ ensure_root (NMDBusManager *dbus_mgr, static void impl_settings_load_connections (NMSettings *self, - char **filenames, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + char **filenames) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GPtrArray *failures; GSList *iter; int i; - if (!ensure_root (priv->dbus_mgr, context)) + if (!ensure_root (nm_bus_manager_get (), context)) return; failures = g_ptr_array_new (); for (i = 0; filenames[i]; i++) { for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { - NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); + NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data); - if (nm_system_config_interface_load_connection (plugin, filenames[i])) + if (nm_settings_plugin_load_connection (plugin, filenames[i])) break; } @@ -1427,40 +1499,110 @@ impl_settings_load_connections (NMSettings *self, } g_ptr_array_add (failures, NULL); - dbus_g_method_return (context, failures->len == 1, failures->pdata); + g_dbus_method_invocation_return_value ( + context, + g_variant_new ("(b^as)", + failures->len == 1, + failures->pdata)); g_ptr_array_unref (failures); } static void impl_settings_reload_connections (NMSettings *self, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); GSList *iter; - if (!ensure_root (priv->dbus_mgr, context)) + if (!ensure_root (nm_bus_manager_get (), context)) return; for (iter = priv->plugins; iter; iter = g_slist_next (iter)) { - NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data); + NMSettingsPlugin *plugin = NM_SETTINGS_PLUGIN (iter->data); - nm_system_config_interface_reload_connections (plugin); + nm_settings_plugin_reload_connections (plugin); } - dbus_g_method_return (context, TRUE); + g_dbus_method_invocation_return_value (context, g_variant_new ("(b)", TRUE)); +} + +static gboolean +write_hostname (NMSettingsPrivate *priv, const char *hostname) +{ + char *hostname_eol; + gboolean ret; + gs_free_error GError *error = NULL; + const char *file = priv->hostname.file; + gs_unref_variant GVariant *var = NULL; +#if HAVE_SELINUX + security_context_t se_ctx_prev = NULL, se_ctx = NULL; + struct stat file_stat = { .st_mode = 0 }; + mode_t st_mode = 0; +#endif + + if (priv->hostname.hostnamed_proxy) { + var = g_dbus_proxy_call_sync (priv->hostname.hostnamed_proxy, + "SetStaticHostname", + g_variant_new ("(sb)", hostname, FALSE), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (error) + nm_log_warn (LOGD_SETTINGS, "Could not set hostname: %s", error->message); + + return !error; + } + +#if HAVE_SELINUX + /* Get default context for hostname file and set it for fscreate */ + if (stat (file, &file_stat) == 0) + st_mode = file_stat.st_mode; + matchpathcon (file, st_mode, &se_ctx); + matchpathcon_fini (); + getfscreatecon (&se_ctx_prev); + setfscreatecon (se_ctx); +#endif + +#if defined (HOSTNAME_PERSIST_GENTOO) + hostname_eol = g_strdup_printf ("#Generated by NetworkManager\n" + "hostname=\"%s\"\n", hostname); +#else + hostname_eol = g_strdup_printf ("%s\n", hostname); +#endif + + /* FIXME: g_file_set_contents() writes first to a temporary file + * and renames it atomically. We should hack g_file_set_contents() + * to set the SELINUX labels before renaming the file. */ + ret = g_file_set_contents (file, hostname_eol, -1, &error); + +#if HAVE_SELINUX + /* Restore previous context and cleanup */ + setfscreatecon (se_ctx_prev); + freecon (se_ctx); + freecon (se_ctx_prev); +#endif + + g_free (hostname_eol); + + if (!ret) { + nm_log_warn (LOGD_SETTINGS, "Could not save hostname to %s: %s", file, error->message); + return FALSE; + } + + return TRUE; } static void pk_hostname_cb (NMAuthChain *chain, GError *chain_error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, gpointer user_data) { NMSettings *self = NM_SETTINGS (user_data); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); NMAuthCallResult result; GError *error = NULL; - GSList *iter; const char *hostname; g_assert (context); @@ -1480,30 +1622,20 @@ pk_hostname_cb (NMAuthChain *chain, NM_SETTINGS_ERROR_PERMISSION_DENIED, "Insufficient privileges."); } else { - /* Set the hostname in all plugins */ hostname = nm_auth_chain_get_data (chain, "hostname"); - for (iter = priv->plugins; iter; iter = iter->next) { - NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE; - /* error will be cleared if any plugin supports saving the hostname */ + if (!write_hostname (priv, hostname)) { error = g_error_new_literal (NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "Saving the hostname failed."); - - g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL); - if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) { - g_object_set (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, hostname, NULL); - g_clear_error (&error); - } } } if (error) - dbus_g_method_return_error (context, error); + g_dbus_method_invocation_take_error (context, error); else - dbus_g_method_return (context); + g_dbus_method_invocation_return_value (context, NULL); - g_clear_error (&error); nm_auth_chain_unref (chain); } @@ -1536,8 +1668,8 @@ validate_hostname (const char *hostname) static void impl_settings_save_hostname (NMSettings *self, - const char *hostname, - DBusGMethodInvocation *context) + GDBusMethodInvocation *context, + const char *hostname) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); NMAuthChain *chain; @@ -1551,14 +1683,6 @@ impl_settings_save_hostname (NMSettings *self, goto done; } - /* Do any of the plugins support setting the hostname? */ - if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME)) { - error = g_error_new_literal (NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_NOT_SUPPORTED, - "None of the registered plugins support setting the hostname."); - goto done; - } - chain = nm_auth_chain_new_context (context, pk_hostname_cb, self); if (!chain) { error = g_error_new_literal (NM_SETTINGS_ERROR, @@ -1573,8 +1697,39 @@ impl_settings_save_hostname (NMSettings *self, done: if (error) - dbus_g_method_return_error (context, error); - g_clear_error (&error); + g_dbus_method_invocation_take_error (context, error); +} + +static void +hostname_maybe_changed (NMSettings *settings) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (settings); + char *new_hostname; + + new_hostname = nm_settings_get_hostname (settings); + + if ( (new_hostname && !priv->hostname.value) + || (!new_hostname && priv->hostname.value) + || (priv->hostname.value && new_hostname && strcmp (priv->hostname.value, new_hostname))) { + + nm_log_info (LOGD_SETTINGS, "hostname changed from %s%s%s to %s%s%s", + NM_PRINT_FMT_QUOTED (priv->hostname.value, "\"", priv->hostname.value, "\"", "(none)"), + NM_PRINT_FMT_QUOTED (new_hostname, "\"", new_hostname, "\"", "(none)")); + g_free (priv->hostname.value); + priv->hostname.value = new_hostname; + g_object_notify (G_OBJECT (settings), NM_SETTINGS_HOSTNAME); + } else + g_free (new_hostname); +} + +static void +hostname_file_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + hostname_maybe_changed (user_data); } static gboolean @@ -1699,13 +1854,20 @@ default_wired_clear_tag (NMSettings *self, nm_config_set_no_auto_default_for_device (NM_SETTINGS_GET_PRIVATE (self)->config, device); } -void -nm_settings_device_added (NMSettings *self, NMDevice *device) +static void +device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self) { NMConnection *connection; NMSettingsConnection *added; GError *error = NULL; + if (!nm_device_is_real (device)) + return; + + g_signal_handlers_disconnect_by_func (device, + G_CALLBACK (device_realized), + self); + /* If the device isn't managed or it already has a default wired connection, * ignore it. */ @@ -1740,7 +1902,19 @@ nm_settings_device_added (NMSettings *self, NMDevice *device) nm_log_info (LOGD_SETTINGS, "(%s): created default wired connection '%s'", nm_device_get_iface (device), - nm_connection_get_id (NM_CONNECTION (added))); + nm_settings_connection_get_id (added)); +} + +void +nm_settings_device_added (NMSettings *self, NMDevice *device) +{ + if (nm_device_is_real (device)) + device_realized (device, NULL, self); + else { + g_signal_connect_after (device, "notify::" NM_DEVICE_REAL, + G_CALLBACK (device_realized), + self); + } } void @@ -1748,6 +1922,10 @@ nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean quittin { NMSettingsConnection *connection; + g_signal_handlers_disconnect_by_func (device, + G_CALLBACK (device_realized), + self); + connection = g_object_get_data (G_OBJECT (device), DEFAULT_WIRED_CONNECTION_TAG); if (connection) { default_wired_clear_tag (self, device, connection, FALSE); @@ -1875,8 +2053,75 @@ nm_settings_get_startup_complete (NMSettings *self) /***************************************************************/ +static void +hostnamed_properties_changed (GDBusProxy *proxy, + GVariant *changed_properties, + char **invalidated_properties, + gpointer user_data) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (user_data); + GVariant *v_hostname; + const char *hostname; + + v_hostname = g_dbus_proxy_get_cached_property (priv->hostname.hostnamed_proxy, + "StaticHostname"); + if (!v_hostname) + return; + + hostname = g_variant_get_string (v_hostname, NULL); + + if (g_strcmp0 (priv->hostname.value, hostname) != 0) { + nm_log_info (LOGD_SETTINGS, "hostname changed from %s%s%s to %s%s%s", + NM_PRINT_FMT_QUOTED (priv->hostname.value, "\"", priv->hostname.value, "\"", "(none)"), + NM_PRINT_FMT_QUOTED (hostname, "\"", hostname, "\"", "(none)")); + g_free (priv->hostname.value); + priv->hostname.value = g_strdup (hostname); + g_object_notify (G_OBJECT (user_data), NM_SETTINGS_HOSTNAME); + nm_dispatcher_call (DISPATCHER_ACTION_HOSTNAME, NULL, NULL, NULL, NULL, NULL, NULL); + } + + g_variant_unref (v_hostname); +} + +static void +setup_hostname_file_monitors (NMSettings *self) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GFileMonitor *monitor; + GFile *file; + + priv->hostname.file = HOSTNAME_FILE; + priv->hostname.value = nm_settings_get_hostname (self); + + /* monitor changes to hostname file */ + file = g_file_new_for_path (priv->hostname.file); + monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref (file); + if (monitor) { + priv->hostname.monitor_id = g_signal_connect (monitor, "changed", + G_CALLBACK (hostname_file_changed_cb), + self); + priv->hostname.monitor = monitor; + } + +#if defined (HOSTNAME_PERSIST_SUSE) + /* monitor changes to dhcp file to know whether the hostname is valid */ + file = g_file_new_for_path (CONF_DHCP); + monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref (file); + if (monitor) { + priv->hostname.dhcp_monitor_id = g_signal_connect (monitor, "changed", + G_CALLBACK (hostname_file_changed_cb), + self); + priv->hostname.dhcp_monitor = monitor; + } +#endif + + hostname_maybe_changed (self); +} + NMSettings * -nm_settings_new (GError **error) +nm_settings_new (void) { NMSettings *self; NMSettingsPrivate *priv; @@ -1886,28 +2131,67 @@ nm_settings_new (GError **error) priv = NM_SETTINGS_GET_PRIVATE (self); priv->config = nm_config_get (); - priv->dbus_mgr = nm_dbus_manager_get (); + + nm_exported_object_export (NM_EXPORTED_OBJECT (self)); + return self; +} + +gboolean +nm_settings_start (NMSettings *self, GError **error) +{ + NMSettingsPrivate *priv; + GDBusProxy *proxy; + GVariant *variant; + GError *local_error = NULL; + + priv = NM_SETTINGS_GET_PRIVATE (self); /* Load the plugins; fail if a plugin is not found. */ if (!load_plugins (self, nm_config_get_plugins (priv->config), error)) { g_object_unref (self); - return NULL; + return FALSE; } load_connections (self); check_startup_complete (self); - nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH_SETTINGS, self); - return self; + proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, 0, NULL, + HOSTNAMED_SERVICE_NAME, HOSTNAMED_SERVICE_PATH, + HOSTNAMED_SERVICE_INTERFACE, NULL, &local_error); + if (proxy) { + variant = g_dbus_proxy_get_cached_property (proxy, "StaticHostname"); + if (variant) { + nm_log_info (LOGD_SETTINGS, "hostname: using hostnamed"); + priv->hostname.hostnamed_proxy = proxy; + g_signal_connect (proxy, "g-properties-changed", + G_CALLBACK (hostnamed_properties_changed), self); + hostnamed_properties_changed (proxy, NULL, NULL, self); + g_variant_unref (variant); + } else { + nm_log_info (LOGD_SETTINGS, "hostname: couldn't get property from hostnamed"); + g_object_unref (proxy); + } + } else { + nm_log_info (LOGD_SETTINGS, "hostname: hostnamed not used as proxy creation failed with: %s", + local_error->message); + g_clear_error (&local_error); + } + + if (!priv->hostname.hostnamed_proxy) + setup_hostname_file_monitors (self); + + priv->started = TRUE; + g_object_notify (G_OBJECT (self), NM_SETTINGS_HOSTNAME); + return TRUE; } static void -connection_provider_init (NMConnectionProvider *cp_class) +connection_provider_iface_init (NMConnectionProviderInterface *cp_iface) { - cp_class->get_best_connections = get_best_connections; - cp_class->get_connections = get_connections; - cp_class->add_connection = _nm_connection_provider_add_connection; - cp_class->get_connection_by_uuid = cp_get_connection_by_uuid; + cp_iface->get_best_connections = get_best_connections; + cp_iface->get_connections = get_connections; + cp_iface->add_connection = _nm_connection_provider_add_connection; + cp_iface->get_connection_by_uuid = cp_get_connection_by_uuid; } static void @@ -1936,10 +2220,34 @@ dispose (GObject *object) g_slist_free_full (priv->auths, (GDestroyNotify) nm_auth_chain_unref); priv->auths = NULL; - priv->dbus_mgr = NULL; - g_object_unref (priv->agent_mgr); + if (priv->hostname.hostnamed_proxy) { + g_signal_handlers_disconnect_by_func (priv->hostname.hostnamed_proxy, + G_CALLBACK (hostnamed_properties_changed), + self); + g_clear_object (&priv->hostname.hostnamed_proxy); + } + + if (priv->hostname.monitor) { + if (priv->hostname.monitor_id) + g_signal_handler_disconnect (priv->hostname.monitor, priv->hostname.monitor_id); + + g_file_monitor_cancel (priv->hostname.monitor); + g_clear_object (&priv->hostname.monitor); + } + + if (priv->hostname.dhcp_monitor) { + if (priv->hostname.dhcp_monitor_id) + g_signal_handler_disconnect (priv->hostname.dhcp_monitor, + priv->hostname.dhcp_monitor_id); + + g_file_monitor_cancel (priv->hostname.dhcp_monitor); + g_clear_object (&priv->hostname.dhcp_monitor); + } + + g_clear_pointer (&priv->hostname.value, g_free); + G_OBJECT_CLASS (nm_settings_parent_class)->dispose (object); } @@ -1962,22 +2270,23 @@ finalize (GObject *object) static void get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) + GValue *value, GParamSpec *pspec) { NMSettings *self = NM_SETTINGS (object); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); const GSList *specs, *iter; - GSList *copy = NULL; GHashTableIter citer; GPtrArray *array; const char *path; switch (prop_id) { case PROP_UNMANAGED_SPECS: + array = g_ptr_array_new (); specs = nm_settings_get_unmanaged_specs (self); for (iter = specs; iter; iter = g_slist_next (iter)) - copy = g_slist_append (copy, g_strdup (iter->data)); - g_value_take_boxed (value, copy); + g_ptr_array_add (array, g_strdup (iter->data)); + g_ptr_array_add (array, NULL); + g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE)); break; case PROP_HOSTNAME: g_value_take_string (value, nm_settings_get_hostname (self)); @@ -1987,14 +2296,15 @@ get_property (GObject *object, guint prop_id, g_value_set_static_string (value, ""); break; case PROP_CAN_MODIFY: - g_value_set_boolean (value, !!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS)); + g_value_set_boolean (value, !!get_plugin (self, NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS)); break; case PROP_CONNECTIONS: - array = g_ptr_array_sized_new (g_hash_table_size (priv->connections)); + array = g_ptr_array_sized_new (g_hash_table_size (priv->connections) + 1); g_hash_table_iter_init (&citer, priv->connections); while (g_hash_table_iter_next (&citer, (gpointer) &path, NULL)) g_ptr_array_add (array, g_strdup (path)); - g_value_take_boxed (value, array); + g_ptr_array_add (array, NULL); + g_value_take_boxed (value, (char **) g_ptr_array_free (array, FALSE)); break; case PROP_STARTUP_COMPLETE: g_value_set_boolean (value, nm_settings_get_startup_complete (self)); @@ -2009,11 +2319,13 @@ static void nm_settings_class_init (NMSettingsClass *class) { GObjectClass *object_class = G_OBJECT_CLASS (class); - + NMExportedObjectClass *exported_object_class = NM_EXPORTED_OBJECT_CLASS (class); + g_type_class_add_private (class, sizeof (NMSettingsPrivate)); + exported_object_class->export_path = NM_DBUS_PATH_SETTINGS; + /* virtual methods */ - object_class->notify = notify; object_class->get_property = get_property; object_class->dispose = dispose; object_class->finalize = finalize; @@ -2023,7 +2335,7 @@ nm_settings_class_init (NMSettingsClass *class) g_object_class_install_property (object_class, PROP_UNMANAGED_SPECS, g_param_spec_boxed (NM_SETTINGS_UNMANAGED_SPECS, "", "", - DBUS_TYPE_G_LIST_OF_STRING, + G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -2044,19 +2356,11 @@ nm_settings_class_init (NMSettingsClass *class) g_object_class_install_property (object_class, PROP_CONNECTIONS, g_param_spec_boxed (NM_SETTINGS_CONNECTIONS, "", "", - DBUS_TYPE_G_ARRAY_OF_OBJECT_PATH, + G_TYPE_STRV, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /* signals */ - signals[PROPERTIES_CHANGED] = - g_signal_new ("properties-changed", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMSettingsClass, properties_changed), - NULL, NULL, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, 1, DBUS_TYPE_G_MAP_OF_VARIANT); signals[CONNECTION_ADDED] = g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_ADDED, G_OBJECT_CLASS_TYPE (object_class), @@ -2064,7 +2368,7 @@ nm_settings_class_init (NMSettingsClass *class) G_STRUCT_OFFSET (NMSettingsClass, connection_added), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); + G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); signals[CONNECTION_UPDATED] = g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_UPDATED, @@ -2073,7 +2377,7 @@ nm_settings_class_init (NMSettingsClass *class) G_STRUCT_OFFSET (NMSettingsClass, connection_updated), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); + G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); signals[CONNECTION_UPDATED_BY_USER] = g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_UPDATED_BY_USER, @@ -2082,7 +2386,7 @@ nm_settings_class_init (NMSettingsClass *class) 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); + G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); signals[CONNECTION_REMOVED] = g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, @@ -2091,7 +2395,7 @@ nm_settings_class_init (NMSettingsClass *class) G_STRUCT_OFFSET (NMSettingsClass, connection_removed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); + G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); signals[CONNECTION_VISIBILITY_CHANGED] = g_signal_new (NM_SETTINGS_SIGNAL_CONNECTION_VISIBILITY_CHANGED, @@ -2100,7 +2404,7 @@ nm_settings_class_init (NMSettingsClass *class) G_STRUCT_OFFSET (NMSettingsClass, connection_visibility_changed), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); + G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); signals[AGENT_REGISTERED] = g_signal_new (NM_SETTINGS_SIGNAL_AGENT_REGISTERED, @@ -2109,7 +2413,7 @@ nm_settings_class_init (NMSettingsClass *class) G_STRUCT_OFFSET (NMSettingsClass, agent_registered), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); + G_TYPE_NONE, 1, NM_TYPE_SECRET_AGENT); signals[NEW_CONNECTION] = @@ -2117,16 +2421,17 @@ nm_settings_class_init (NMSettingsClass *class) G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, G_TYPE_OBJECT); - - dbus_g_error_domain_register (NM_SETTINGS_ERROR, - NM_DBUS_INTERFACE_SETTINGS, - NM_TYPE_SETTINGS_ERROR); - dbus_g_error_domain_register (NM_CONNECTION_ERROR, - NM_DBUS_INTERFACE_SETTINGS_CONNECTION, - NM_TYPE_CONNECTION_ERROR); - - dbus_g_object_type_install_info (NM_TYPE_SETTINGS, &dbus_glib_nm_settings_object_info); - + G_TYPE_NONE, 1, NM_TYPE_SETTINGS_CONNECTION); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (class), + NMDBUS_TYPE_SETTINGS_SKELETON, + "ListConnections", impl_settings_list_connections, + "GetConnectionByUuid", impl_settings_get_connection_by_uuid, + "AddConnection", impl_settings_add_connection, + "AddConnectionUnsaved", impl_settings_add_connection_unsaved, + "LoadConnections", impl_settings_load_connections, + "ReloadConnections", impl_settings_reload_connections, + "SaveHostname", impl_settings_save_hostname, + NULL); } diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index d196efe6..923b164b 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -28,7 +28,7 @@ #include -#include "nm-types.h" +#include "nm-exported-object.h" #define NM_TYPE_SETTINGS (nm_settings_get_type ()) #define NM_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTINGS, NMSettings)) @@ -51,11 +51,11 @@ #define NM_SETTINGS_SIGNAL_AGENT_REGISTERED "agent-registered" struct _NMSettings { - GObject parent_instance; + NMExportedObject parent_instance; }; typedef struct { - GObjectClass parent_class; + NMExportedObjectClass parent_class; /* Signals */ void (*properties_changed) (NMSettings *self, GHashTable *properties); @@ -73,7 +73,8 @@ typedef struct { GType nm_settings_get_type (void); -NMSettings *nm_settings_new (GError **error); +NMSettings *nm_settings_new (void); +gboolean nm_settings_start (NMSettings *self, GError **error); typedef void (*NMSettingsForEachFunc) (NMSettings *settings, NMSettingsConnection *connection, @@ -86,13 +87,14 @@ void nm_settings_for_each_connection (NMSettings *settings, typedef void (*NMSettingsAddCallback) (NMSettings *settings, NMSettingsConnection *connection, GError *error, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, + NMAuthSubject *subject, gpointer user_data); void nm_settings_add_connection_dbus (NMSettings *self, NMConnection *connection, gboolean save_to_disk, - DBusGMethodInvocation *context, + GDBusMethodInvocation *context, NMSettingsAddCallback callback, gpointer user_data); @@ -111,7 +113,7 @@ NMSettingsConnection *nm_settings_get_connection_by_path (NMSettings *settings, NMSettingsConnection *nm_settings_get_connection_by_uuid (NMSettings *settings, const char *uuid); -gboolean nm_settings_has_connection (NMSettings *self, NMConnection *connection); +gboolean nm_settings_has_connection (NMSettings *self, NMSettingsConnection *connection); const GSList *nm_settings_get_unmanaged_specs (NMSettings *self); diff --git a/src/settings/nm-system-config-interface.c b/src/settings/nm-system-config-interface.c deleted file mode 100644 index 637c301e..00000000 --- a/src/settings/nm-system-config-interface.c +++ /dev/null @@ -1,216 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * 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) 2007 - 2011 Red Hat, Inc. - * Copyright (C) 2008 Novell, Inc. - */ - -#include "config.h" - -#include "nm-system-config-interface.h" -#include "nm-settings-connection.h" - -static void -interface_init (gpointer g_iface) -{ - GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); - static gboolean initialized = FALSE; - - if (initialized) - return; - - /* Properties */ - g_object_interface_install_property - (g_iface, - g_param_spec_string (NM_SYSTEM_CONFIG_INTERFACE_NAME, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_interface_install_property - (g_iface, - g_param_spec_string (NM_SYSTEM_CONFIG_INTERFACE_INFO, "", "", - NULL, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_interface_install_property - (g_iface, - g_param_spec_uint (NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, "", "", - NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE, - ( NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS - | NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME), - NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - - g_object_interface_install_property - (g_iface, - g_param_spec_string (NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, "", "", - NULL, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - - /* Signals */ - g_signal_new (NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMSystemConfigInterface, connection_added), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, - NM_TYPE_SETTINGS_CONNECTION); - - g_signal_new (NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED, - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMSystemConfigInterface, unmanaged_specs_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - g_signal_new (NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED, - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMSystemConfigInterface, unrecognized_specs_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - initialized = TRUE; -} - - -GType -nm_system_config_interface_get_type (void) -{ - static GType system_config_interface_type = 0; - - if (!system_config_interface_type) { - const GTypeInfo system_config_interface_info = { - sizeof (NMSystemConfigInterface), /* class_size */ - interface_init, /* base_init */ - NULL, /* base_finalize */ - NULL, - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL - }; - - system_config_interface_type = g_type_register_static (G_TYPE_INTERFACE, - "NMSystemConfigInterface", - &system_config_interface_info, - 0); - - g_type_interface_add_prerequisite (system_config_interface_type, G_TYPE_OBJECT); - } - - return system_config_interface_type; -} - -void -nm_system_config_interface_init (NMSystemConfigInterface *config, - gpointer unused) -{ - g_return_if_fail (config != NULL); - - if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->init) - NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->init (config); -} - -GSList * -nm_system_config_interface_get_connections (NMSystemConfigInterface *config) -{ - g_return_val_if_fail (config != NULL, NULL); - - if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->get_connections) - return NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->get_connections (config); - return NULL; -} - -gboolean -nm_system_config_interface_load_connection (NMSystemConfigInterface *config, - const char *filename) -{ - g_return_val_if_fail (config != NULL, FALSE); - - if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->load_connection) - return NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->load_connection (config, filename); - return FALSE; -} - -void -nm_system_config_interface_reload_connections (NMSystemConfigInterface *config) -{ - g_return_if_fail (config != NULL); - - if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->reload_connections) - NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->reload_connections (config); -} - -GSList * -nm_system_config_interface_get_unmanaged_specs (NMSystemConfigInterface *config) -{ - g_return_val_if_fail (config != NULL, NULL); - - if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->get_unmanaged_specs) - return NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->get_unmanaged_specs (config); - return NULL; -} - -GSList * -nm_system_config_interface_get_unrecognized_specs (NMSystemConfigInterface *config) -{ - g_return_val_if_fail (config != NULL, NULL); - - if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->get_unrecognized_specs) - return NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->get_unrecognized_specs (config); - return NULL; -} - -/** - * nm_system_config_interface_add_connection: - * @config: the #NMSystemConfigInterface - * @connection: the source connection to create a plugin-specific - * #NMSettingsConnection from - * @save_to_disk: %TRUE to save the connection to disk immediately, %FALSE to - * not save to disk - * @error: on return, a location to store any errors that may occur - * - * Creates a new #NMSettingsConnection for the given source @connection. If the - * plugin cannot handle the given connection type, it should return %NULL and - * set @error. The plugin owns the returned object and the caller must reference - * the object if it wishes to continue using it. - * - * Returns: the new #NMSettingsConnection or %NULL - */ -NMSettingsConnection * -nm_system_config_interface_add_connection (NMSystemConfigInterface *config, - NMConnection *connection, - gboolean save_to_disk, - GError **error) -{ - g_return_val_if_fail (config != NULL, NULL); - g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); - - if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection) - return NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->add_connection (config, connection, save_to_disk, error); - - return NULL; -} diff --git a/src/settings/nm-system-config-interface.h b/src/settings/nm-system-config-interface.h deleted file mode 100644 index 144aadbf..00000000 --- a/src/settings/nm-system-config-interface.h +++ /dev/null @@ -1,166 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * 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) 2007 - 2011 Red Hat, Inc. - * Copyright (C) 2008 Novell, Inc. - */ - -#ifndef __NETWORKMANAGER_SYSTEM_CONFIG_INTERFACE_H__ -#define __NETWORKMANAGER_SYSTEM_CONFIG_INTERFACE_H__ - -#include -#include -#include -#include "nm-types.h" - -G_BEGIN_DECLS - -/* Plugin's factory function that returns a GObject that implements - * NMSystemConfigInterface. - */ -GObject * nm_system_config_factory (void); - -#define NM_TYPE_SYSTEM_CONFIG_INTERFACE (nm_system_config_interface_get_type ()) -#define NM_SYSTEM_CONFIG_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SYSTEM_CONFIG_INTERFACE, NMSystemConfigInterface)) -#define NM_IS_SYSTEM_CONFIG_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SYSTEM_CONFIG_INTERFACE)) -#define NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_SYSTEM_CONFIG_INTERFACE, NMSystemConfigInterface)) - - -#define NM_SYSTEM_CONFIG_INTERFACE_NAME "name" -#define NM_SYSTEM_CONFIG_INTERFACE_INFO "info" -#define NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES "capabilities" -#define NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME "hostname" - -#define NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED "unmanaged-specs-changed" -#define NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED "unrecognized-specs-changed" -#define NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED "connection-added" - -typedef enum { - NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE = 0x00000000, - NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS = 0x00000001, - NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME = 0x00000002 - - /* When adding more capabilities, be sure to update the "Capabilities" - * property max value in nm-system-config-interface.c. - */ -} NMSystemConfigInterfaceCapabilities; - -typedef enum { - NM_SYSTEM_CONFIG_INTERFACE_PROP_FIRST = 0x1000, - - NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME = NM_SYSTEM_CONFIG_INTERFACE_PROP_FIRST, - NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, - NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES, - NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME, -} NMSystemConfigInterfaceProp; - - -typedef struct _NMSystemConfigInterface NMSystemConfigInterface; - -struct _NMSystemConfigInterface { - GTypeInterface g_iface; - - /* Called when the plugin is loaded to initialize it */ - void (*init) (NMSystemConfigInterface *config); - - /* Returns a GSList of NMSettingsConnection objects that represent - * connections the plugin knows about. The returned list is freed by the - * system settings service. - */ - GSList * (*get_connections) (NMSystemConfigInterface *config); - - /* Requests that the plugin load/reload a single connection, if it - * recognizes the filename. Returns success or failure. - */ - gboolean (*load_connection) (NMSystemConfigInterface *config, - const char *filename); - - /* Requests that the plugin reload all connection files from disk, - * and emit signals reflecting new, changed, and removed connections. - */ - void (*reload_connections) (NMSystemConfigInterface *config); - - /* - * Return a string list of specifications of devices which NetworkManager - * should not manage. Returned list will be freed by the system settings - * service, and each element must be allocated using g_malloc() or its - * variants (g_strdup, g_strdup_printf, etc). - * - * Each string in the list must be in one of the formats recognized by - * nm_device_spec_match_list(). - */ - GSList * (*get_unmanaged_specs) (NMSystemConfigInterface *config); - - /* - * Return a string list of specifications of devices for which at least - * one non-NetworkManager-based configuration is defined. Returned list - * will be freed by the system settings service, and each element must be - * allocated using g_malloc() or its variants (g_strdup, g_strdup_printf, - * etc). - * - * Each string in the list must be in one of the formats recognized by - * nm_device_spec_match_list(). - */ - GSList * (*get_unrecognized_specs) (NMSystemConfigInterface *config); - - /* - * Initialize the plugin-specific connection and return a new - * NMSettingsConnection subclass that contains the same settings as the - * original connection. The connection should only be saved to backing - * storage if @save_to_disk is TRUE. The returned object is owned by the - * plugin and must be referenced by the owner if necessary. - */ - NMSettingsConnection * (*add_connection) (NMSystemConfigInterface *config, - NMConnection *connection, - gboolean save_to_disk, - GError **error); - - /* Signals */ - - /* Emitted when a new connection has been found by the plugin */ - void (*connection_added) (NMSystemConfigInterface *config, - NMSettingsConnection *connection); - - /* Emitted when the list of unmanaged device specifications changes */ - void (*unmanaged_specs_changed) (NMSystemConfigInterface *config); - - /* Emitted when the list of devices with unrecognized connections changes */ - void (*unrecognized_specs_changed) (NMSystemConfigInterface *config); -}; - -GType nm_system_config_interface_get_type (void); - -void nm_system_config_interface_init (NMSystemConfigInterface *config, - gpointer unused); - -GSList *nm_system_config_interface_get_connections (NMSystemConfigInterface *config); - -gboolean nm_system_config_interface_load_connection (NMSystemConfigInterface *config, - const char *filename); -void nm_system_config_interface_reload_connections (NMSystemConfigInterface *config); - -GSList *nm_system_config_interface_get_unmanaged_specs (NMSystemConfigInterface *config); -GSList *nm_system_config_interface_get_unrecognized_specs (NMSystemConfigInterface *config); - -NMSettingsConnection *nm_system_config_interface_add_connection (NMSystemConfigInterface *config, - NMConnection *connection, - gboolean save_to_disk, - GError **error); - -G_END_DECLS - -#endif /* NM_SYSTEM_CONFIG_INTERFACE_H */ diff --git a/src/settings/plugins/Makefile.am b/src/settings/plugins/Makefile.am index 568da7f6..278d455d 100644 --- a/src/settings/plugins/Makefile.am +++ b/src/settings/plugins/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS=keyfile example +SUBDIRS=keyfile @GNOME_CODE_COVERAGE_RULES@ @@ -10,10 +10,6 @@ if CONFIG_PLUGIN_IFCFG_RH SUBDIRS+=ifcfg-rh endif -if CONFIG_PLUGIN_IFCFG_SUSE -SUBDIRS+=ifcfg-suse -endif - if CONFIG_PLUGIN_IFUPDOWN SUBDIRS+=ifupdown endif diff --git a/src/settings/plugins/Makefile.in b/src/settings/plugins/Makefile.in index c706214b..643e0da7 100644 --- a/src/settings/plugins/Makefile.in +++ b/src/settings/plugins/Makefile.in @@ -89,9 +89,8 @@ build_triplet = @build@ host_triplet = @host@ @CONFIG_PLUGIN_IBFT_TRUE@am__append_1 = ibft @CONFIG_PLUGIN_IFCFG_RH_TRUE@am__append_2 = ifcfg-rh -@CONFIG_PLUGIN_IFCFG_SUSE_TRUE@am__append_3 = ifcfg-suse -@CONFIG_PLUGIN_IFUPDOWN_TRUE@am__append_4 = ifupdown -@CONFIG_PLUGIN_IFNET_TRUE@am__append_5 = ifnet +@CONFIG_PLUGIN_IFUPDOWN_TRUE@am__append_3 = ifupdown +@CONFIG_PLUGIN_IFNET_TRUE@am__append_4 = ifnet subdir = src/settings/plugins ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ @@ -168,8 +167,8 @@ am__define_uniq_tagged_files = \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags -DIST_SUBDIRS = keyfile example ibft ifcfg-rh ifcfg-suse ifupdown ifnet -am__DIST_COMMON = $(srcdir)/Makefile.in +DIST_SUBDIRS = keyfile ibft ifcfg-rh ifupdown ifnet +am__DIST_COMMON = $(srcdir)/Makefile.in README DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ @@ -211,7 +210,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -223,8 +221,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -234,6 +230,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -288,16 +285,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -334,6 +328,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -362,7 +358,6 @@ 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@ @@ -377,6 +372,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -437,6 +434,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -444,6 +442,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -459,8 +458,8 @@ with_dhcpcd = @with_dhcpcd@ with_netconfig = @with_netconfig@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ -SUBDIRS = keyfile example $(am__append_1) $(am__append_2) \ - $(am__append_3) $(am__append_4) $(am__append_5) +SUBDIRS = keyfile $(am__append_1) $(am__append_2) $(am__append_3) \ + $(am__append_4) all: all-recursive .SUFFIXES: diff --git a/src/settings/plugins/README b/src/settings/plugins/README new file mode 100644 index 00000000..307d0bb1 --- /dev/null +++ b/src/settings/plugins/README @@ -0,0 +1,33 @@ +Plugins generally have three components: + +1) plugin object: manages the individual "connections", which are + just objects wrapped around on-disk config data. The plugin handles requests + to add new connections via the NM D-Bus API, and also watches config + directories for changes to configuration data. Plugins implement the + NMSettingsPlugin interface. See plugin.c. + +2) "connections": subclasses of NMSettingsConnection. They handle updates to + configuration data, deletion, etc. See NMKeyfileConnection. + +3) reader/writer code: typically a separate static library that gets linked + into the main plugin shared object, so they can be unit tested separately + from the plugin. This code should read config data from disk and create + an NMConnection from it, and be capable of taking an NMConnection and writing + out appropriate configuration data to disk. + +NM will first call the "factory" function that every module must provide, which +is nm_settings_plugin_factory(). That function creates and returns a singleton +instance of the plugin's main object, which implements NMSettingsPlugin. +That interface is implemented via the object definition in G_DEFINE_TYPE_EXTENDED +in plugin.c, which registers the interface setup function +settings_plugin_interface_init(), which when called actually sets up the vtables +for the functions defined by NMSettingsPluginInterface. Thus there are two +entry points into the plugin: nm_settings_plugin_factory() and +the NMSettingsPluginInterface methods. + +The plugin also emits various signals (defined by NMSettingsPluginInterface) +which NetworkManager listens for. These include notifications of new +connections if they were created via changes to the on-disk files. The +"connection" objects can also emit signals (defined by the NMSettingsConnection +and NMConnection superclasses) when the connections' backing storage gets +changed or deleted. diff --git a/src/settings/plugins/example/Makefile.am b/src/settings/plugins/example/Makefile.am deleted file mode 100644 index 7ce8eaea..00000000 --- a/src/settings/plugins/example/Makefile.am +++ /dev/null @@ -1,33 +0,0 @@ -AM_CPPFLAGS = \ - -I$(top_srcdir)/src \ - -I$(top_srcdir)/src/settings \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ - -I$(top_srcdir)/libnm-core \ - -I$(top_builddir)/libnm-core \ - -DG_LOG_DOMAIN=\""NetworkManager-example"\" \ - -DNETWORKMANAGER_COMPILATION \ - -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) \ - -DNMCONFDIR=\"$(nmconfdir)\" - -# 'noinst' here because this is an example plugin we don't want to install -noinst_LTLIBRARIES = libnm-settings-plugin-example.la - -# The actual plugins typically pull reader.c and writer.c out into -# their own static library so that unit tests can use them without -# having to build the entire plugin. But since this is a simple -# plugin we don't do that yet. - -libnm_settings_plugin_example_la_SOURCES = \ - nm-example-connection.c \ - nm-example-connection.h \ - plugin.c \ - plugin.h \ - common.h \ - reader.c \ - writer.c - -libnm_settings_plugin_example_la_LDFLAGS = -module -avoid-version - diff --git a/src/settings/plugins/example/Makefile.in b/src/settings/plugins/example/Makefile.in deleted file mode 100644 index 5f16d186..00000000 --- a/src/settings/plugins/example/Makefile.in +++ /dev/null @@ -1,779 +0,0 @@ -# Makefile.in generated by automake 1.15 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2014 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 = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -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/settings/plugins/example -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) -DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -LTLIBRARIES = $(noinst_LTLIBRARIES) -libnm_settings_plugin_example_la_LIBADD = -am_libnm_settings_plugin_example_la_OBJECTS = \ - nm-example-connection.lo plugin.lo reader.lo writer.lo -libnm_settings_plugin_example_la_OBJECTS = \ - $(am_libnm_settings_plugin_example_la_OBJECTS) -AM_V_lt = $(am__v_lt_@AM_V@) -am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) -am__v_lt_0 = --silent -am__v_lt_1 = -libnm_settings_plugin_example_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) \ - $(libnm_settings_plugin_example_la_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(CFLAGS) -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = -CCLD = $(CC) -LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = -SOURCES = $(libnm_settings_plugin_example_la_SOURCES) -DIST_SOURCES = $(libnm_settings_plugin_example_la_SOURCES) -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -am__DIST_COMMON = $(srcdir)/Makefile.in \ - $(top_srcdir)/build-aux/depcomp README -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -ALL_LINGUAS = @ALL_LINGUAS@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AM_TESTS_FD_REDIRECT = @AM_TESTS_FD_REDIRECT@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BLUEZ5_CFLAGS = @BLUEZ5_CFLAGS@ -BLUEZ5_LIBS = @BLUEZ5_LIBS@ -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@ -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_CHECK_PATH = @GTKDOC_CHECK_PATH@ -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@ -LOG_DRIVER = @LOG_DRIVER@ -LTLIBICONV = @LTLIBICONV@ -LTLIBINTL = @LTLIBINTL@ -LTLIBOBJS = @LTLIBOBJS@ -LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ -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_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ -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@ -PERL = @PERL@ -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_DIR = @UDEV_DIR@ -USE_NLS = @USE_NLS@ -UUID_CFLAGS = @UUID_CFLAGS@ -UUID_LIBS = @UUID_LIBS@ -VALGRIND_RULES = @VALGRIND_RULES@ -VAPIGEN = @VAPIGEN@ -VAPIGEN_MAKEFILE = @VAPIGEN_MAKEFILE@ -VAPIGEN_VAPIDIR = @VAPIGEN_VAPIDIR@ -VERSION = @VERSION@ -XGETTEXT = @XGETTEXT@ -XGETTEXT_015 = @XGETTEXT_015@ -XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_CXX = @ac_ct_CXX@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -intltool__v_merge_options_ = @intltool__v_merge_options_@ -intltool__v_merge_options_0 = @intltool__v_merge_options_0@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -nmbinary = @nmbinary@ -nmconfdir = @nmconfdir@ -nmdatadir = @nmdatadir@ -nmrundir = @nmrundir@ -nmstatedir = @nmstatedir@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -subdirs = @subdirs@ -sysconfdir = @sysconfdir@ -systemdsystemunitdir = @systemdsystemunitdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -with_dhclient = @with_dhclient@ -with_dhcpcd = @with_dhcpcd@ -with_netconfig = @with_netconfig@ -with_resolvconf = @with_resolvconf@ -with_valgrind = @with_valgrind@ -AM_CPPFLAGS = \ - -I$(top_srcdir)/src \ - -I$(top_srcdir)/src/settings \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ - -I$(top_srcdir)/libnm-core \ - -I$(top_builddir)/libnm-core \ - -DG_LOG_DOMAIN=\""NetworkManager-example"\" \ - -DNETWORKMANAGER_COMPILATION \ - -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) \ - -DNMCONFDIR=\"$(nmconfdir)\" - - -# 'noinst' here because this is an example plugin we don't want to install -noinst_LTLIBRARIES = libnm-settings-plugin-example.la - -# The actual plugins typically pull reader.c and writer.c out into -# their own static library so that unit tests can use them without -# having to build the entire plugin. But since this is a simple -# plugin we don't do that yet. -libnm_settings_plugin_example_la_SOURCES = \ - nm-example-connection.c \ - nm-example-connection.h \ - plugin.c \ - plugin.h \ - common.h \ - reader.c \ - writer.c - -libnm_settings_plugin_example_la_LDFLAGS = -module -avoid-version -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/settings/plugins/example/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/settings/plugins/example/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-noinstLTLIBRARIES: - -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) - @list='$(noinst_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } - -libnm-settings-plugin-example.la: $(libnm_settings_plugin_example_la_OBJECTS) $(libnm_settings_plugin_example_la_DEPENDENCIES) $(EXTRA_libnm_settings_plugin_example_la_DEPENDENCIES) - $(AM_V_CCLD)$(libnm_settings_plugin_example_la_LINK) $(libnm_settings_plugin_example_la_OBJECTS) $(libnm_settings_plugin_example_la_LIBADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-example-connection.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reader.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/writer.Plo@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< - -.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 -o $@ `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-am - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-am - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(LTLIBRARIES) -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-noinstLTLIBRARIES \ - 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: install-am install-strip - -.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ - clean-libtool clean-noinstLTLIBRARIES 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 - -.PRECIOUS: Makefile - - -# 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/settings/plugins/example/README b/src/settings/plugins/example/README deleted file mode 100644 index 224814d1..00000000 --- a/src/settings/plugins/example/README +++ /dev/null @@ -1,35 +0,0 @@ -Plugins generally have three components: - -1) plugin object: manages the individual "connections", which are - just objects wrapped around on-disk config data. The plugin handles requests - to add new connections via the NM D-Bus API, and also watches config - directories for changes to configuration data. It also handles reading and - writing the persistent hostname, if the plugin supports hostnames. Plugins - implement the NMSystemConfigInterface interface. See plugin.c. - -2) "connections": subclasses of NMSettingsConnection. They handle updates to - configuration data, deletion, etc. See NMExampleConnection.c. - -3) reader/writer code: typically a separate static library that gets linked - into the main plugin shared object, so they can be unit tested separately - from the plugin. This code should read config data from disk and create - an NMConnection from it, and be capable of taking an NMConnection and writing - out appropriate configuration data to disk. - -NM will first call the "factory" function that every module must provide, which -is nm_system_config_factory(). That function creates and returns a singleton -instance of the plugin's main object, which implements NMSystemConfigInterface. -That interface is implemented via the object definition in G_DEFINE_TYPE_EXTENDED -in plugin.c, which registers the interface setup function -system_config_interface_init(), which when called actually sets up the vtables -for the functions defined by NMSystemConfigInterface. Thus there are two -entry points into the plugin: nm_system_config_factory() and -the NMSystemConfigInterface methods. - -The plugin also emits various signals (defined by NMSystemConfigInterface) -which NetworkManager listens for. These include persistent hostname changes -(if something modified the file in which the persistent hostname is stored) -and notifications of new connections if they were created via changes to -the on-disk files. The "connection" objects can also emit signals -(defined by the NMSettingsConnection and NMConnection superclasses) when the -connections' backing storage gets changed or deleted. diff --git a/src/settings/plugins/example/common.h b/src/settings/plugins/example/common.h deleted file mode 100644 index cf209fe0..00000000 --- a/src/settings/plugins/example/common.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * 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. - * - * (C) Copyright 2012 Red Hat, Inc. - */ - -#ifndef __COMMON_H__ -#define __COMMON_H__ - -#include - -#include - -/* General info about the plugin that the code may want to use for logging - * purposes. - */ -#define EXAMPLE_PLUGIN_NAME "example" -#define EXAMPLE_PLUGIN_INFO "(c) 2012 Red Hat, Inc. To report bugs please use the NetworkManager mailing list." - -#define EXAMPLE_DIR NMCONFDIR "/example-plugin" - -/* Prototypes for the reader/writer functions */ -NMConnection *connection_from_file (const char *filename, GError **error); - -gboolean write_connection (NMConnection *connection, - const char *existing_path, - char **out_path, - GError **error); - -#endif /* __COMMON_H__ */ - diff --git a/src/settings/plugins/example/nm-example-connection.c b/src/settings/plugins/example/nm-example-connection.c deleted file mode 100644 index e1259611..00000000 --- a/src/settings/plugins/example/nm-example-connection.c +++ /dev/null @@ -1,189 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - keyfile plugin - * - * 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) 2012 Red Hat, Inc. - */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "nm-system-config-interface.h" -#include "nm-dbus-glib-types.h" -#include "nm-example-connection.h" -#include "common.h" - -/* GObject boilerplate; this object is a subclass of NMSettingsConnection - * which is specified by the NM_TYPE_SETTINGS_CONNECTION bit here. That - * in turn is a subclass of NMConnection, so it ends up that NMExampleConnection - * is a subclass of NMConnection too. - */ -G_DEFINE_TYPE (NMExampleConnection, nm_example_connection, NM_TYPE_SETTINGS_CONNECTION) - -#define NM_EXAMPLE_CONNECTION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_EXAMPLE_CONNECTION, NMExampleConnectionPrivate)) - -/* Object private instance data */ -typedef struct { - char *path; -} NMExampleConnectionPrivate; - - -/* Creates a new object which encapsulates an on-disk connection and any - * plugin-specific operations or data. - */ -NMExampleConnection * -nm_example_connection_new (const char *full_path, - NMConnection *source, - GError **error) -{ - GObject *object; - NMExampleConnectionPrivate *priv; - NMConnection *tmp; - const char *uuid; - - g_return_val_if_fail (full_path != NULL, NULL); - - /* If we're given a connection already, prefer that instead of re-reading */ - if (source) - tmp = g_object_ref (source); - else { - /* Read the data offdisk and translate it into a simple NMConnection object */ - tmp = connection_from_file (full_path, error); - if (!tmp) - return NULL; - } - - /* Actually create the new NMExampleConnection object */ - object = (GObject *) g_object_new (NM_TYPE_EXAMPLE_CONNECTION, NULL); - priv = NM_EXAMPLE_CONNECTION_GET_PRIVATE (object); - priv->path = g_strdup (full_path); - - /* Update our settings with what was read from the file or what got passed - * in as a source NMConnection. - */ - if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), - tmp, - TRUE, - NULL, - error)) { - g_object_unref (object); - object = NULL; - goto out; - } - - /* Make sure we have a UUID; just a sanity check */ - uuid = nm_connection_get_uuid (NM_CONNECTION (object)); - if (!uuid) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Connection in file %s had no UUID", full_path); - g_object_unref (object); - object = NULL; - } - -out: - g_object_unref (tmp); - return (NMExampleConnection *) object; -} - -const char * -nm_example_connection_get_path (NMExampleConnection *self) -{ - g_return_val_if_fail (NM_IS_EXAMPLE_CONNECTION (self), NULL); - - /* Simple accessor that returns the file path from our private instance data */ - return NM_EXAMPLE_CONNECTION_GET_PRIVATE (self)->path; -} - -static void -commit_changes (NMSettingsConnection *connection, - NMSettingsConnectionCommitFunc callback, - gpointer user_data) -{ - NMExampleConnectionPrivate *priv = NM_EXAMPLE_CONNECTION_GET_PRIVATE (connection); - char *path = NULL; - GError *error = NULL; - - /* Write the new connection data out to disk. This function passes - * back the path of the file it wrote out so that we know what that - * path is if the connection is a completely new one. - */ - if (!write_connection (NM_CONNECTION (connection), priv->path, &path, &error)) { - callback (connection, error, user_data); - g_clear_error (&error); - return; - } - - /* Update the filename if it changed */ - if (path) { - g_free (priv->path); - priv->path = path; - } - - /* Chain up to parent for generic commit stuff */ - NM_SETTINGS_CONNECTION_CLASS (nm_example_connection_parent_class)->commit_changes (connection, - callback, - user_data); -} - -static void -do_delete (NMSettingsConnection *connection, - NMSettingsConnectionDeleteFunc callback, - gpointer user_data) -{ - NMExampleConnectionPrivate *priv = NM_EXAMPLE_CONNECTION_GET_PRIVATE (connection); - - g_unlink (priv->path); - - /* Chain up to parent for generic deletion stuff */ - NM_SETTINGS_CONNECTION_CLASS (nm_example_connection_parent_class)->delete (connection, - callback, - user_data); -} - -/**************************************************************/ - -static void -nm_example_connection_init (NMExampleConnection *connection) -{ -} - -static void -finalize (GObject *object) -{ - g_free (NM_EXAMPLE_CONNECTION_GET_PRIVATE (object)->path); - - G_OBJECT_CLASS (nm_example_connection_parent_class)->finalize (object); -} - -static void -nm_example_connection_class_init (NMExampleConnectionClass *keyfile_connection_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (keyfile_connection_class); - NMSettingsConnectionClass *settings_class = NM_SETTINGS_CONNECTION_CLASS (keyfile_connection_class); - - /* Tells GObject to allocate and zero our instance data pointer */ - g_type_class_add_private (keyfile_connection_class, sizeof (NMExampleConnectionPrivate)); - - /* Overrides of various superclass methods */ - object_class->finalize = finalize; - settings_class->commit_changes = commit_changes; - settings_class->delete = do_delete; -} diff --git a/src/settings/plugins/example/nm-example-connection.h b/src/settings/plugins/example/nm-example-connection.h deleted file mode 100644 index ddbd7ac2..00000000 --- a/src/settings/plugins/example/nm-example-connection.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - keyfile plugin - * - * 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) 2012 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_EXAMPLE_CONNECTION_H__ -#define __NETWORKMANAGER_EXAMPLE_CONNECTION_H__ - -#include - -G_BEGIN_DECLS - -/* GObject boilerplate */ -#define NM_TYPE_EXAMPLE_CONNECTION (nm_example_connection_get_type ()) -#define NM_EXAMPLE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_EXAMPLE_CONNECTION, NMExampleConnection)) -#define NM_EXAMPLE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_EXAMPLE_CONNECTION, NMExampleConnectionClass)) -#define NM_IS_EXAMPLE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_EXAMPLE_CONNECTION)) -#define NM_IS_EXAMPLE_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_EXAMPLE_CONNECTION)) -#define NM_EXAMPLE_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_EXAMPLE_CONNECTION, NMExampleConnectionClass)) - -typedef struct { - NMSettingsConnection parent; -} NMExampleConnection; - -typedef struct { - NMSettingsConnectionClass parent; -} NMExampleConnectionClass; - -GType nm_example_connection_get_type (void); - -/* Actual API that plugin.c will call */ -NMExampleConnection *nm_example_connection_new (const char *filename, - NMConnection *source, - GError **error); - -const char *nm_example_connection_get_path (NMExampleConnection *self); - -G_END_DECLS - -#endif /* __NETWORKMANAGER_EXAMPLE_CONNECTION_H__ */ diff --git a/src/settings/plugins/example/plugin.c b/src/settings/plugins/example/plugin.c deleted file mode 100644 index 0bcb38fc..00000000 --- a/src/settings/plugins/example/plugin.c +++ /dev/null @@ -1,858 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - keyfile plugin - * - * 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) 2012 Red Hat, Inc. - */ - -#include "config.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "plugin.h" -#include "nm-system-config-interface.h" -#include "common.h" -#include "nm-example-connection.h" - -static char *plugin_get_hostname (SCPluginExample *plugin); -static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class); - -/* GObject object definition. This actually defines the object and tells - * GObject about the interfaces this object provides. Here we provide - * the "system config interface" which is the API that NetworkManager uses - * to communicate with this plugin. - * - * Interface and super/sub-class access with GObject works via casting and - * GObject magically figures out what needs to be called. So, given: - * - * SCPluginExample *plugin = ; - * - * you can call GObject methods since SCPluginExample inherits from GObject - * via the G_TYPE_OBJECT argument of G_DEFINE_TYPE_EXTENDED below: - * - * g_object_set_data (G_OBJECT (plugin), ...); - * - * and since SCPluginExample implements NMSystemConfigInterface via the - * G_IMPLEMENT_INTERFACE bit below, we can also call any methods of - * NMSystemConfigInterface (defined in NM sources in nm-system-config-interface.c): - * - * connections = nm_system_config_interface_get_connections (NM_SYSTEM_CONFIG_INTERFACE (plugin)); - * - * For the call to nm_system_config_interface_get_connections() that eventually - * ends up in the get_connections() method in this file because the - * system_config_interface_init() function sets up the vtable for this objects - * implementation of NMSystemConfigInterface. - */ -G_DEFINE_TYPE_EXTENDED (SCPluginExample, sc_plugin_example, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, system_config_interface_init)) - -/* Quick define to access the object's private data pointer; this pointer - * points to the object's instance data. - */ -#define SC_PLUGIN_EXAMPLE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_EXAMPLE, SCPluginExamplePrivate)) - -/* Instance data. When the object is created, a new structure of this type - * will be created and zeroed for this instance of the object to use. This - * is actually done by g_type_class_add_private() when called from the object's - * class init function. - */ -typedef struct { - /* This hash holds each connection known to this plugin */ - GHashTable *connections; - - /* A watch for changes on the directory that holds the configuration files - * so the plugin can respond to configuration changes on-the-fly and - * tell NM that the connection data has changed. Typically the plugin - * needs to monitor the directory itself (to watch for completely new files) - * while the individual connections watch their individual config files. - */ - GFileMonitor *monitor; - guint monitor_id; - - /* Tracks changes to the global NM config file, just in case our - * plugin has some specific options (like unmanaged devices) that - * might be changed at runtime. - */ - const char *conf_file; - GFileMonitor *conf_file_monitor; - guint conf_file_monitor_id; - - /* Persistent hostname if the plugin supports hostnames. Normally used - * for distro plugins; ie Red Hat uses /etc/sysconfig/hostname while - * Debian uses /etc/hostname. Plugins can abstract the storage location - * and just tell NM what the persisten hostname is and when its backing - * file has changed. NM handles actually setting the hostname. - */ - char *hostname; -} SCPluginExamplePrivate; - -static NMSettingsConnection * -_internal_new_connection (SCPluginExample *self, - const char *full_path, - NMConnection *source, - GError **error) -{ - SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (self); - NMExampleConnection *connection; - - g_return_val_if_fail (full_path != NULL, NULL); - - /* 'source' will usually be NULL if we're going to read the connection - * off disk. But if the new connection is coming from NetworkManager - * (ie, from a D-Bus AddConnection request) then we'll have 'source' too. - * This function expects the connection to already be written to disk - * so that the NMExampleConnection object can re-read it and intialize - * state in the same manner as when getting a change notification from - * the config directory. That simplifies things somewhat. - */ - - connection = nm_example_connection_new (full_path, source, error); - if (connection) { - g_hash_table_insert (priv->connections, - g_strdup (nm_example_connection_get_path (connection)), - connection); - } - - return (NMSettingsConnection *) connection; -} - -/* Read each file in our config directory and try to create a new - * NMExamplePlugin for it. - */ -static void -read_connections (NMSystemConfigInterface *config) -{ - SCPluginExample *self = SC_PLUGIN_EXAMPLE (config); - GDir *dir; - GError *error = NULL; - const char *item; - - dir = g_dir_open (EXAMPLE_DIR, 0, &error); - if (!dir) { - nm_log_warn (LOGD_SETTINGS, "Cannot read directory '%s': (%d) %s", - EXAMPLE_DIR, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - return; - } - - while ((item = g_dir_read_name (dir))) { - NMSettingsConnection *connection; - char *full_path; - - /* XXX: Check file extension and ignore "~", ".tmp", ".bak", etc */ - - full_path = g_build_filename (EXAMPLE_DIR, item, NULL); - nm_log_info (LOGD_SETTINGS, "parsing %s ... ", item); - - connection = _internal_new_connection (self, full_path, NULL, &error); - if (connection) { - nm_log_info (LOGD_SETTINGS, " read connection '%s'", - nm_connection_get_id (NM_CONNECTION (connection))); - } else { - nm_log_info (LOGD_SETTINGS, " error: %s", - (error && error->message) ? error->message : "(unknown)"); - } - g_clear_error (&error); - g_free (full_path); - } - g_dir_close (dir); -} - -static void -update_connection_settings_commit_cb (NMSettingsConnection *orig, GError *error, gpointer user_data) -{ - /* If there was an error updating the connection's internal stuff, then - * we can't do anything except log it and remove the connection. This might - * happen due to invalid data, but as the data would already have been - * verified before it ever got to this plugin, we shouldn't ever get - * an error here. - */ - if (error) { - nm_log_warn (LOGD_SETTINGS, "%s: connection invalid: %s", - __func__, error->message); - g_clear_error (&error); - - nm_settings_connection_signal_remove (orig); - } -} - -static void -update_connection_settings (NMExampleConnection *orig, - NMExampleConnection *new) -{ - /* This just replaces the orig's internal settings with those from new */ - nm_settings_connection_replace_and_commit (NM_SETTINGS_CONNECTION (orig), - NM_CONNECTION (new), - update_connection_settings_commit_cb, NULL); -} - -/* Monitoring */ - -static void -remove_connection (SCPluginExample *self, - NMExampleConnection *connection, - const char *name) -{ - g_return_if_fail (connection != NULL); - g_return_if_fail (name != NULL); - - /* Removing from the hash table should drop the last reference, but since - * we need the object to stay alive across the signal emission to NM, - * we grab a temporary reference. - */ - g_object_ref (connection); - g_hash_table_remove (SC_PLUGIN_EXAMPLE_GET_PRIVATE (self)->connections, name); - - /* Tell NM the connection is gone */ - nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection)); - - /* Remove the temporary reference; connection will now be destroyed */ - g_object_unref (connection); -} - -/* Look through all connections we know about and return one with a given UUID */ -static NMExampleConnection * -find_by_uuid (SCPluginExample *self, const char *uuid) -{ - SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (self); - GHashTableIter iter; - gpointer data = NULL; - - g_return_val_if_fail (uuid != NULL, NULL); - - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, NULL, &data)) { - NMConnection *candidate = NM_CONNECTION (data); - - if (strcmp (uuid, nm_connection_get_uuid (candidate)) == 0) - return NM_EXAMPLE_CONNECTION (candidate); - } - return NULL; -} - - -static void -dir_changed (GFileMonitor *monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer user_data) -{ - NMSystemConfigInterface *config = NM_SYSTEM_CONFIG_INTERFACE (user_data); - SCPluginExample *self = SC_PLUGIN_EXAMPLE (config); - SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (self); - char *full_path; - NMExampleConnection *connection; - GError *error = NULL; - - full_path = g_file_get_path (file); - /* XXX: Check here if you need to ignore this file, ie by checking for - * extensions like "~" and ".bak" or ".tmp". If so just return; - */ - - /* Check if we know about this connection already */ - connection = g_hash_table_lookup (priv->connections, full_path); - - switch (event_type) { - case G_FILE_MONITOR_EVENT_DELETED: - if (connection) { - nm_log_info (LOGD_SETTINGS, "removed %s.", full_path); - remove_connection (SC_PLUGIN_EXAMPLE (config), connection, full_path); - } - break; - case G_FILE_MONITOR_EVENT_CREATED: - case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: - if (connection) { - /* Update of an existing connection. Here we re-read the file and - * compare it against the existing connection to check if anything - * actually changed. - */ - NMExampleConnection *tmp; - - tmp = nm_example_connection_new (full_path, NULL, &error); - if (tmp) { - if (!nm_connection_compare (NM_CONNECTION (connection), - NM_CONNECTION (tmp), - NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS | - NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) { - /* Connection changed; update our internal connection object */ - nm_log_info (LOGD_SETTINGS, "updating %s", full_path); - update_connection_settings (connection, tmp); - } - g_object_unref (tmp); - } else { - /* There was an error parsing the updated connection; it may - * no longer be valid and thus we've got to delete it. If it - * becomes valid again later we'll get another change - * notification, we'll re-read it, and we'll treat it as new. - */ - nm_log_info (LOGD_SETTINGS, " error: %s", - (error && error->message) ? error->message : "(unknown)"); - remove_connection (SC_PLUGIN_EXAMPLE (config), connection, full_path); - } - g_clear_error (&error); - } else { - nm_log_info (LOGD_SETTINGS, "updating %s", full_path); - - /* We don't know about the connection yet, so the change represents - * a completely new connection. - */ - connection = nm_example_connection_new (full_path, NULL, &error); - if (connection) { - NMExampleConnection *found = NULL; - - /* Connection renames will show up as different files but with - * the same UUID. Try to find the original connection. - * A connection rename is treated just like an update except - * there's a bit more housekeeping with the hash table. - */ - found = find_by_uuid (self, nm_connection_get_uuid (NM_CONNECTION (connection))); - if (found) { - const char *old_path = nm_example_connection_get_path (connection); - - /* Removing from the hash table should drop the last reference, - * but of course we want to keep the connection around. - */ - g_object_ref (found); - g_hash_table_remove (priv->connections, old_path); - - /* Updating settings should update the NMExampleConnection's - * filename property too. - */ - update_connection_settings (found, connection); - - /* Re-insert the connection back into the hash with the new filename */ - g_hash_table_insert (priv->connections, - g_strdup (nm_example_connection_get_path (found)), - found); - - /* Get rid of the temporary connection */ - g_object_unref (connection); - } else { - /* Completely new connection, not a rename. */ - g_hash_table_insert (priv->connections, - g_strdup (nm_example_connection_get_path (connection)), - connection); - /* Tell NM we found a new connection */ - g_signal_emit_by_name (config, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection); - } - } else { - nm_log_info (LOGD_SETTINGS, " error: %s", (error && error->message) ? error->message : "(unknown)"); - g_clear_error (&error); - } - } - break; - default: - break; - } - - g_free (full_path); -} - -static void -conf_file_changed (GFileMonitor *monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer data) -{ - SCPluginExample *self = SC_PLUGIN_EXAMPLE (data); - SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (self); - char *tmp; - - switch (event_type) { - case G_FILE_MONITOR_EVENT_DELETED: - case G_FILE_MONITOR_EVENT_CREATED: - case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: - /* Unmanaged devices option may have changed; just emit the changed - * signal for unmanaged specs and when NM calls back in to get the - * updated specs we'll re-read the config file then. - */ - g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); - - /* Hostname may also have changed; read it and if it did actually - * change, notify NM. - */ - tmp = plugin_get_hostname (self); - if (g_strcmp0 (tmp, priv->hostname) != 0) { - g_free (priv->hostname); - priv->hostname = tmp; - tmp = NULL; - g_object_notify (G_OBJECT (self), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); - } - g_free (tmp); - break; - default: - break; - } -} - -/* This function starts the inotify monitors that watch the plugin's config - * file directory for new connections and changes to existing connections - * (if not disabled by NetworkManager.conf), and for changes to the plugin's - * non-connection config files. - */ -static void -setup_monitoring (NMSystemConfigInterface *config) -{ - SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (config); - GFileMonitor *monitor; - GFile *file; - - /* Initialize connection hash here; we use the connection hash as the - * "are we initialized yet" variable. - */ - priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); - - if (nm_config_get_monitor_connection_files (nm_config_get ())) { - /* Set up the watch for our config directory */ - file = g_file_new_for_path (EXAMPLE_DIR); - monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); - g_object_unref (file); - if (monitor) { - /* This registers the dir_changed() function to be called whenever - * the GFileMonitor object notices a change in the directory. - */ - priv->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (dir_changed), config); - priv->monitor = monitor; - } - } - - /* Set up a watch on our configuration file, basically just for watching - * whether the user has changed the unmanaged devices option or the - * persistent hostname. - */ - if (priv->conf_file) { - file = g_file_new_for_path (priv->conf_file); - monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); - g_object_unref (file); - - if (monitor) { - priv->conf_file_monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (conf_file_changed), config); - priv->conf_file_monitor = monitor; - } - } -} - -/*******************************************************************/ - -/* Return to NM the full list of connections this plugin owns */ -static GSList * -get_connections (NMSystemConfigInterface *config) -{ - SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (config); - GHashTableIter iter; - NMSettingsConnection *connection; - GSList *list = NULL; - - if (!priv->connections) { - /* If we haven't read connections in yet, do so now */ - setup_monitoring (config); - read_connections (config); - } - - /* Add each connection from our internal hash table to a list returned - * to NetworkManager. - */ - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &connection)) - list = g_slist_prepend (list, connection); - return list; -} - -/* Called by NetworkManager when a user adds a new connection via D-Bus. - * The plugin should convert the data in 'connection' to its on-disk format - * write it out to disk, and return an object that's a subclass of - * NMSettingsConnection. Typically plugins will subclass NMSettingsConnection - * and use that class to handle any plugin-specific stuff like monitoring - * the on-disk config files for changes, and/or parsing the file-format and - * converting back and forth from that to NMConnection. - */ -static NMSettingsConnection * -add_connection (NMSystemConfigInterface *config, - NMConnection *connection, - gboolean save_to_disk, - GError **error) -{ - SCPluginExample *self = SC_PLUGIN_EXAMPLE (config); - NMSettingsConnection *added = NULL; - char *path = NULL; - - /* Write it out first, then add the connection to our internal list; that - * way we don't trigger the new NMSettingsConnection subclass' file watch - * functions needlessly. - */ - if (save_to_disk && !write_connection (connection, NULL, &path, error)) - return NULL; - - added = _internal_new_connection (self, path, connection, error); - g_free (path); - return added; -} - -/* This function returns a list of "unmanaged device specs" which represent - * a list of devices that NetworkManager should not manage. Each unmanaged - * spec item has a specific format starting with a "tag" and followed by - * tag-specific data. The only currently specified items are "mac:" followed - * by the MAC address of the interface NM should not manage, or "interface-name:" - * followed by the name of the interface NM should not manage. This function - * reads the list of unmanaged devices from wherever the plugin wants to - * store them and returns that list to NetworkManager. - */ -static GSList * -get_unmanaged_specs (NMSystemConfigInterface *config) -{ - SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (config); - GKeyFile *key_file; - GSList *specs = NULL; - GError *error = NULL; - char *str, **ids; - int i; - - if (!priv->conf_file) - return NULL; - - key_file = g_key_file_new (); - if (!g_key_file_load_from_file (key_file, priv->conf_file, G_KEY_FILE_NONE, &error)) { - nm_log_warn (LOGD_SETTINGS, "Error parsing file '%s': %s", priv->conf_file, error->message); - g_error_free (error); - goto out; - } - - - str = g_key_file_get_value (key_file, "keyfile", "unmanaged-devices", NULL); - if (!str) - goto out; - - ids = g_strsplit (str, ";", -1); - for (i = 0; ids[i] != NULL; i++) { - /* Verify unmanaged specification and add it to the list */ - if (!strncmp (ids[i], "mac:", 4) && nm_utils_hwaddr_valid (ids[i] + 4, -1)) { - specs = g_slist_append (specs, ids[i]); - } else if (!strncmp (ids[i], "interface-name:", 15) && nm_utils_iface_valid_name (ids[i] + 15)) { - specs = g_slist_append (specs, ids[i]); - } else { - nm_log_warn (LOGD_SETTINGS, "Error in file '%s': invalid unmanaged-devices entry: '%s'", priv->conf_file, ids[i]); - g_free (ids[i]); - } - } - - g_free (ids); /* Yes, g_free, not g_strfreev because we need the strings in the list */ - g_free (str); - -out: - g_key_file_free (key_file); - return specs; -} - - -static char * -plugin_get_hostname (SCPluginExample *plugin) -{ - SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (plugin); - GKeyFile *key_file; - char *hostname = NULL; - GError *error = NULL; - - if (!priv->conf_file) - return NULL; - - /* Read the persistent hostname out of backing storage, which happens - * to be the NM config file. Other plugins (like distro-specific ones) - * should read it from the distro-specific location like /etc/hostname. - */ - key_file = g_key_file_new (); - if (g_key_file_load_from_file (key_file, priv->conf_file, G_KEY_FILE_NONE, &error)) - hostname = g_key_file_get_value (key_file, "keyfile", "hostname", NULL); - else { - nm_log_warn (LOGD_SETTINGS, "Error parsing file '%s': %s", priv->conf_file, error->message); - g_error_free (error); - } - - g_key_file_free (key_file); - return hostname; -} - -static gboolean -plugin_set_hostname (SCPluginExample *plugin, const char *hostname) -{ - SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (plugin); - GKeyFile *key_file; - GError *error = NULL; - gboolean success = FALSE; - char *data; - gsize len; - - if (!priv->conf_file) { - nm_log_warn (LOGD_SETTINGS, "Error saving hostname: no config file"); - return FALSE; - } - - /* This just saves the hostname to the NM config file in a section - * private to this plugin. - */ - key_file = g_key_file_new (); - if (!g_key_file_load_from_file (key_file, priv->conf_file, G_KEY_FILE_NONE, &error)) { - nm_log_warn (LOGD_SETTINGS, "Error parsing file '%s': %s", priv->conf_file, error->message); - g_error_free (error); - goto out; - } - - g_key_file_set_string (key_file, "example", "hostname", hostname); - - data = g_key_file_to_data (key_file, &len, &error); - if (data) { - /* Save updated file to disk */ - g_file_set_contents (priv->conf_file, data, len, &error); - g_free (data); - - /* Update internal copy of hostname */ - g_free (priv->hostname); - priv->hostname = g_strdup (hostname); - success = TRUE; - } - - if (error) { - nm_log_warn (LOGD_SETTINGS, "Error saving hostname: %s", error->message); - g_error_free (error); - } - -out: - g_key_file_free (key_file); - return success; -} - -/* GObject */ - -static void -sc_plugin_example_init (SCPluginExample *plugin) -{ - /* Here we'd do any instance-specific initialization like setting - * members of SCPluginExamplePrivate to default values. But we - * don't have anything to do here since most initialization is done - * when NM calls the various entry points. - */ -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - switch (prop_id) { - case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME: - g_value_set_string (value, EXAMPLE_PLUGIN_NAME); - break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO: - g_value_set_string (value, EXAMPLE_PLUGIN_INFO); - break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES: - /* Return capabilities to NM; this plugin supports changing connections - * as well as being capable of saving the hostname to persistent storage. - * If the plugin can't write out updated configuration, then obviously - * it shouldn't advertise that capability. If it can't save hostnames - * to persistent storage, it shouldn't advertise that capability either. - */ - g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS | - NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME); - break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME: - /* Return the hostname we've read from persistent storage */ - g_value_set_string (value, SC_PLUGIN_EXAMPLE_GET_PRIVATE (object)->hostname); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - const char *hostname; - - switch (prop_id) { - case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME: - /* We'll get here when the user has changed the hostname via NM's - * D-Bus interface and we're requested to save this hostname to - * persistent storage. - */ - hostname = g_value_get_string (value); - if (hostname && strlen (hostname) < 1) - hostname = NULL; - plugin_set_hostname (SC_PLUGIN_EXAMPLE (object), hostname); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -dispose (GObject *object) -{ - SCPluginExamplePrivate *priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (object); - - /* GObject has a two-stage object destruction process: dispose and finalize. - * In dispose the object should free any references it might have on other - * objects to break circular refs, then it's finally cleaned up by finalize. - * We don't bother to implement a finalize, so we just make sure that we - * clean everything up (including clearing pointers) in dispose so that - * if GObject decides to revive this object post-dispose (yes, legal) - * we don't crash on dangling pointers. - */ - - if (priv->monitor) { - if (priv->monitor_id) { - g_signal_handler_disconnect (priv->monitor, priv->monitor_id); - priv->monitor_id = 0; - } - - g_file_monitor_cancel (priv->monitor); - g_object_unref (priv->monitor); - priv->monitor = NULL; - } - - if (priv->conf_file_monitor) { - if (priv->conf_file_monitor_id) { - g_signal_handler_disconnect (priv->conf_file_monitor, priv->conf_file_monitor_id); - priv->conf_file_monitor_id = 0; - } - - g_file_monitor_cancel (priv->conf_file_monitor); - g_object_unref (priv->conf_file_monitor); - priv->conf_file_monitor = NULL; - } - - if (priv->connections) { - /* Destroying the connections hash unrefs each connection in it - * due to the GHashTable value_destroy_func that we passed into - * g_hash_table_new_full(). - */ - g_hash_table_destroy (priv->connections); - priv->connections = NULL; - } - - g_free (priv->hostname); - priv->hostname = NULL; - - /* Chain up to the superclass */ - G_OBJECT_CLASS (sc_plugin_example_parent_class)->dispose (object); -} - -/* This function gets called to set up any method and property overrides - * of superclasses, and also (if we actually had any) to set up any - * custom properties and signals this object might have. This is called before - * the object is actually instantiated; it just sets up the generic class - * stuff, not anything related to a specific object instance. - */ -static void -sc_plugin_example_class_init (SCPluginExampleClass *req_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (req_class); - - /* This actually creates and zeros the object's instance data struct */ - g_type_class_add_private (req_class, sizeof (SCPluginExamplePrivate)); - - /* Override GObject base class methods with our custom implementations */ - object_class->dispose = dispose; - object_class->get_property = get_property; - object_class->set_property = set_property; - - /* Override various GObject properties that we need to change. Here we - * just tell GObject that we will be handling the get/set operations for - * these specific properties. They are actually defined by the - * NMSystemConfigInterface interface in nm-system-config-interface.c. - * What happens here is that we tell GObject that for a given property - * name (ie NM_SYSTEM_CONFIG_INTERFACE_NAME) we'll be using the enum value - * NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME locally in get_property() and - * set_property(). - */ - g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME, - NM_SYSTEM_CONFIG_INTERFACE_NAME); - - g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, - NM_SYSTEM_CONFIG_INTERFACE_INFO); - - g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES, - NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES); - - g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME, - NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); -} - -static void -system_config_interface_init (NMSystemConfigInterface *sci_intf) -{ - /* Interface implementation for NMSystemConfigInterface. This sets - * up the GInterface vtable that lets GObject know what functions to - * call for each method of the NMSystemConfigInterface interface. - */ - sci_intf->get_connections = get_connections; - sci_intf->add_connection = add_connection; - sci_intf->get_unmanaged_specs = get_unmanaged_specs; -} - -/*******************************************************************/ - -/* Factory function: this is the first entry point for NetworkManager, which - * gets called during NM startup to create the instance of this plugin - * that NetworkManager will actually use. Since every plugin is a singleton - * we just return a singleton instance. This function should never be called - * twice. - */ -G_MODULE_EXPORT GObject * -nm_system_config_factory (void) -{ - static SCPluginExample *singleton = NULL; - SCPluginExamplePrivate *priv; - - if (!singleton) { - /* Instantiate our plugin */ - singleton = SC_PLUGIN_EXAMPLE (g_object_new (SC_TYPE_PLUGIN_EXAMPLE, NULL)); - priv = SC_PLUGIN_EXAMPLE_GET_PRIVATE (singleton); - - /* Cache the config file path */ - priv->conf_file = nm_config_data_get_config_main_file (nm_config_get_data (nm_config_get ())); - } else { - /* This function should never be called twice */ - g_assert_not_reached (); - } - - return G_OBJECT (singleton); -} - diff --git a/src/settings/plugins/example/plugin.h b/src/settings/plugins/example/plugin.h deleted file mode 100644 index f10ee1c4..00000000 --- a/src/settings/plugins/example/plugin.h +++ /dev/null @@ -1,55 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - example plugin - * - * 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) 2012 Red Hat, Inc. - */ - -#ifndef _PLUGIN_H_ -#define _PLUGIN_H_ - -#include - -/* GObject boilerplate: you usually only need to rename 'example' here to - * your plugin's name. These functions get used when casting pointers - * to your plugin's object type. - */ -#define SC_TYPE_PLUGIN_EXAMPLE (sc_plugin_example_get_type ()) -#define SC_PLUGIN_EXAMPLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_EXAMPLE, SCPluginExample)) -#define SC_PLUGIN_EXAMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_EXAMPLE, SCPluginExampleClass)) -#define SC_IS_PLUGIN_EXAMPLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_EXAMPLE)) -#define SC_IS_PLUGIN_EXAMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_PLUGIN_EXAMPLE)) -#define SC_PLUGIN_EXAMPLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_EXAMPLE, SCPluginExampleClass)) - -typedef struct { - /* GObject instance structure for the plugin; we don't do anything special - * here so this object's instance is exactly the same as its parent. - */ - GObject parent; -} SCPluginExample; - -typedef struct { - /* GObject class structure; we don't do anything special here - * so this object's class is exactly the same as its parent. Typically - * if the plugin implemented custom signals their prototypes would go - * here, but most plugins don't need to do this. - */ - GObjectClass parent; -} SCPluginExampleClass; - -GType sc_plugin_example_get_type (void); - -#endif /* _PLUGIN_H_ */ diff --git a/src/settings/plugins/example/reader.c b/src/settings/plugins/example/reader.c deleted file mode 100644 index ee45440a..00000000 --- a/src/settings/plugins/example/reader.c +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * 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) 2012 Red Hat, Inc. - */ - -#include "config.h" - -#include - -#include -#include - -#include "common.h" - -NMConnection * -connection_from_file (const char *filename, GError **error) -{ - /* This function should, given a file path, read that file and convert its - * data into an NMConnection. There are two approaches to this. First, - * if the plugin data format is similar to the NMConnection internal - * format, you can get away with calling nm_connection_for_each_setting_value() - * to iterate through every possible setting's keys and read that value - * from the plugin's format. If the plugin's format is siginificantly - * different then you may have to build up the connection manually by - * determining the type of connection from the on-disk data, creating - * each setting object, adding the values, then adding that setting to - * the NMConnection. - */ - - return NULL; -} - diff --git a/src/settings/plugins/example/writer.c b/src/settings/plugins/example/writer.c deleted file mode 100644 index 41e5c498..00000000 --- a/src/settings/plugins/example/writer.c +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * 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) 2012 Red Hat, Inc. - */ - -#include "config.h" - -#include - -#include - -#include "common.h" - -gboolean -write_connection (NMConnection *connection, - const char *existing_path, - char **out_path, - GError **error) -{ - /* This function should take the NMConnection and convert it to the format - * which this plugin uses on-disk and then write out that data. It returns - * the file path of the file that represents this connection data so that - * the plugin can track it for change notification and updates. If - * 'existing_path' is given we can assume that this is an update of an - * existing connection and not a completely new one. - */ - - /* There are two approaches to converting the data. The first more manual - * approach consists of grabbing each setting value from the NMConnection - * and converting it into the appropriate value for the plugin's data - * format. This is usually taken by distro plugins because their format - * is significantly different than NetworkManager's internal format. - * The second uses nm_connection_for_each_setting_value() to iterate - * through each value of each setting in the NMConnection, convert it to - * the required format, and write it out, but this requires that the - * plugin format more closely follow the NetworkManager internal format. - */ - - return FALSE; -} - diff --git a/src/settings/plugins/ibft/Makefile.am b/src/settings/plugins/ibft/Makefile.am index 6bc9d05d..a994808d 100644 --- a/src/settings/plugins/ibft/Makefile.am +++ b/src/settings/plugins/ibft/Makefile.am @@ -14,14 +14,13 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/ \ -I$(top_srcdir)/src/platform \ -I$(top_srcdir)/src/settings \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) \ -DG_LOG_DOMAIN=\""NetworkManager-ibft"\" \ -DSYSCONFDIR=\"$(sysconfdir)\" \ -DSBINDIR=\"$(sbindir)\" diff --git a/src/settings/plugins/ibft/Makefile.in b/src/settings/plugins/ibft/Makefile.in index 1f5b8eb4..024442b1 100644 --- a/src/settings/plugins/ibft/Makefile.in +++ b/src/settings/plugins/ibft/Makefile.in @@ -277,7 +277,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -289,8 +288,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -300,6 +297,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -354,16 +352,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -400,6 +395,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -428,7 +425,6 @@ 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@ @@ -443,6 +439,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -503,6 +501,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -510,6 +509,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -536,14 +536,13 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/ \ -I$(top_srcdir)/src/platform \ -I$(top_srcdir)/src/settings \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) \ -DG_LOG_DOMAIN=\""NetworkManager-ibft"\" \ -DSYSCONFDIR=\"$(sysconfdir)\" \ -DSBINDIR=\"$(sbindir)\" diff --git a/src/settings/plugins/ibft/plugin.c b/src/settings/plugins/ibft/plugin.c index 632c4df1..555725d1 100644 --- a/src/settings/plugins/ibft/plugin.c +++ b/src/settings/plugins/ibft/plugin.c @@ -25,39 +25,38 @@ #include #include -#include -#include -#include #include -#include "nm-dbus-glib-types.h" -#include "nm-system-config-interface.h" -#include "nm-logging.h" +#include "nm-default.h" +#include "nm-settings-plugin.h" #include "NetworkManagerUtils.h" #include "plugin.h" #include "reader.h" #include "nm-ibft-connection.h" -static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class); +static void settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface); -G_DEFINE_TYPE_EXTENDED (SCPluginIbft, sc_plugin_ibft, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, - system_config_interface_init)) +G_DEFINE_TYPE_EXTENDED (SettingsPluginIbft, settings_plugin_ibft, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN, + settings_plugin_interface_init)) -#define SC_PLUGIN_IBFT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_IBFT, SCPluginIbftPrivate)) +#define SETTINGS_PLUGIN_IBFT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SETTINGS_TYPE_PLUGIN_IBFT, SettingsPluginIbftPrivate)) typedef struct { GHashTable *connections; /* uuid::connection */ gboolean initialized; -} SCPluginIbftPrivate; +} SettingsPluginIbftPrivate; + +static SettingsPluginIbft *settings_plugin_ibft_get (void); +NM_DEFINE_SINGLETON_GETTER (SettingsPluginIbft, settings_plugin_ibft_get, SETTINGS_TYPE_PLUGIN_IBFT); static void -read_connections (SCPluginIbft *self) +read_connections (SettingsPluginIbft *self) { - SCPluginIbftPrivate *priv = SC_PLUGIN_IBFT_GET_PRIVATE (self); + SettingsPluginIbftPrivate *priv = SETTINGS_PLUGIN_IBFT_GET_PRIVATE (self); GSList *blocks = NULL, *iter; GError *error = NULL; NMIbftConnection *connection; @@ -86,10 +85,10 @@ read_connections (SCPluginIbft *self) } static GSList * -get_connections (NMSystemConfigInterface *config) +get_connections (NMSettingsPlugin *config) { - SCPluginIbft *self = SC_PLUGIN_IBFT (config); - SCPluginIbftPrivate *priv = SC_PLUGIN_IBFT_GET_PRIVATE (self); + SettingsPluginIbft *self = SETTINGS_PLUGIN_IBFT (config); + SettingsPluginIbftPrivate *priv = SETTINGS_PLUGIN_IBFT_GET_PRIVATE (self); GSList *list = NULL; GHashTableIter iter; NMIbftConnection *connection; @@ -107,14 +106,14 @@ get_connections (NMSystemConfigInterface *config) } static void -init (NMSystemConfigInterface *config) +init (NMSettingsPlugin *config) { } static void -sc_plugin_ibft_init (SCPluginIbft *self) +settings_plugin_ibft_init (SettingsPluginIbft *self) { - SCPluginIbftPrivate *priv = SC_PLUGIN_IBFT_GET_PRIVATE (self); + SettingsPluginIbftPrivate *priv = SETTINGS_PLUGIN_IBFT_GET_PRIVATE (self); priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } @@ -122,15 +121,15 @@ sc_plugin_ibft_init (SCPluginIbft *self) static void dispose (GObject *object) { - SCPluginIbft *self = SC_PLUGIN_IBFT (object); - SCPluginIbftPrivate *priv = SC_PLUGIN_IBFT_GET_PRIVATE (self); + SettingsPluginIbft *self = SETTINGS_PLUGIN_IBFT (object); + SettingsPluginIbftPrivate *priv = SETTINGS_PLUGIN_IBFT_GET_PRIVATE (self); if (priv->connections) { g_hash_table_destroy (priv->connections); priv->connections = NULL; } - G_OBJECT_CLASS (sc_plugin_ibft_parent_class)->dispose (object); + G_OBJECT_CLASS (settings_plugin_ibft_parent_class)->dispose (object); } static void @@ -138,14 +137,14 @@ get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { - case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME: + case NM_SETTINGS_PLUGIN_PROP_NAME: g_value_set_string (value, "iBFT"); break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO: + case NM_SETTINGS_PLUGIN_PROP_INFO: g_value_set_string (value, "(c) 2014 Red Hat, Inc. To report bugs please use the NetworkManager mailing list."); break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES: - g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE); + case NM_SETTINGS_PLUGIN_PROP_CAPABILITIES: + g_value_set_uint (value, NM_SETTINGS_PLUGIN_CAP_NONE); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -161,50 +160,39 @@ set_property (GObject *object, guint prop_id, } static void -sc_plugin_ibft_class_init (SCPluginIbftClass *req_class) +settings_plugin_ibft_class_init (SettingsPluginIbftClass *req_class) { GObjectClass *object_class = G_OBJECT_CLASS (req_class); - g_type_class_add_private (req_class, sizeof (SCPluginIbftPrivate)); + g_type_class_add_private (req_class, sizeof (SettingsPluginIbftPrivate)); object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME, - NM_SYSTEM_CONFIG_INTERFACE_NAME); - - g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, - NM_SYSTEM_CONFIG_INTERFACE_INFO); + NM_SETTINGS_PLUGIN_PROP_NAME, + NM_SETTINGS_PLUGIN_NAME); g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES, - NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES); + NM_SETTINGS_PLUGIN_PROP_INFO, + NM_SETTINGS_PLUGIN_INFO); g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME, - NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); + NM_SETTINGS_PLUGIN_PROP_CAPABILITIES, + NM_SETTINGS_PLUGIN_CAPABILITIES); } static void -system_config_interface_init (NMSystemConfigInterface *system_config_interface_class) +settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) { /* interface implementation */ - system_config_interface_class->get_connections = get_connections; - system_config_interface_class->init = init; + plugin_iface->get_connections = get_connections; + plugin_iface->init = init; } G_MODULE_EXPORT GObject * -nm_system_config_factory (void) +nm_settings_plugin_factory (void) { - static SCPluginIbft *singleton = NULL; - - if (!singleton) - singleton = SC_PLUGIN_IBFT (g_object_new (SC_TYPE_PLUGIN_IBFT, NULL)); - else - g_object_ref (singleton); - - return G_OBJECT (singleton); + return g_object_ref (settings_plugin_ibft_get ()); } diff --git a/src/settings/plugins/ibft/plugin.h b/src/settings/plugins/ibft/plugin.h index 2c811359..3fc58c7f 100644 --- a/src/settings/plugins/ibft/plugin.h +++ b/src/settings/plugins/ibft/plugin.h @@ -21,27 +21,27 @@ #ifndef _PLUGIN_H_ #define _PLUGIN_H_ -#include +#include "nm-default.h" -#define SC_TYPE_PLUGIN_IBFT (sc_plugin_ibft_get_type ()) -#define SC_PLUGIN_IBFT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_IBFT, SCPluginIbft)) -#define SC_PLUGIN_IBFT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_IBFT, SCPluginIbftClass)) -#define SC_IS_PLUGIN_IBFT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_IBFT)) -#define SC_IS_PLUGIN_IBFT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_PLUGIN_IBFT)) -#define SC_PLUGIN_IBFT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_IBFT, SCPluginIbftClass)) +#define SETTINGS_TYPE_PLUGIN_IBFT (settings_plugin_ibft_get_type ()) +#define SETTINGS_PLUGIN_IBFT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SETTINGS_TYPE_PLUGIN_IBFT, SettingsPluginIbft)) +#define SETTINGS_PLUGIN_IBFT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SETTINGS_TYPE_PLUGIN_IBFT, SettingsPluginIbftClass)) +#define SETTINGS_IS_PLUGIN_IBFT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SETTINGS_TYPE_PLUGIN_IBFT)) +#define SETTINGS_IS_PLUGIN_IBFT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SETTINGS_TYPE_PLUGIN_IBFT)) +#define SETTINGS_PLUGIN_IBFT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SETTINGS_TYPE_PLUGIN_IBFT, SettingsPluginIbftClass)) -typedef struct _SCPluginIbft SCPluginIbft; -typedef struct _SCPluginIbftClass SCPluginIbftClass; +typedef struct _SettingsPluginIbft SettingsPluginIbft; +typedef struct _SettingsPluginIbftClass SettingsPluginIbftClass; -struct _SCPluginIbft { +struct _SettingsPluginIbft { GObject parent; }; -struct _SCPluginIbftClass { +struct _SettingsPluginIbftClass { GObjectClass parent; }; -GType sc_plugin_ibft_get_type (void); +GType settings_plugin_ibft_get_type (void); #endif /* _PLUGIN_H_ */ diff --git a/src/settings/plugins/ibft/reader.c b/src/settings/plugins/ibft/reader.c index 9bc63462..195c2641 100644 --- a/src/settings/plugins/ibft/reader.c +++ b/src/settings/plugins/ibft/reader.c @@ -31,13 +31,10 @@ #include #include -#include -#include - +#include "nm-default.h" #include "nm-core-internal.h" #include "nm-platform.h" #include "NetworkManagerUtils.h" -#include "nm-logging.h" #include "reader.h" diff --git a/src/settings/plugins/ibft/reader.h b/src/settings/plugins/ibft/reader.h index 0b2f22b6..42969ae0 100644 --- a/src/settings/plugins/ibft/reader.h +++ b/src/settings/plugins/ibft/reader.h @@ -21,9 +21,10 @@ #ifndef __READER_H__ #define __READER_H__ -#include #include +#include "nm-default.h" + gboolean read_ibft_blocks (const char *iscsiadm_path, GSList **out_blocks, GError **error); diff --git a/src/settings/plugins/ibft/tests/Makefile.am b/src/settings/plugins/ibft/tests/Makefile.am index 9901119e..29881e85 100644 --- a/src/settings/plugins/ibft/tests/Makefile.am +++ b/src/settings/plugins/ibft/tests/Makefile.am @@ -5,8 +5,8 @@ if ENABLE_TESTS AM_CPPFLAGS = \ $(GLIB_CFLAGS) \ $(CODE_COVERAGE_CFLAGS) \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -I$(top_srcdir)/src/ \ @@ -14,14 +14,13 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/settings \ -I$(srcdir)/../ \ -DG_LOG_DOMAIN=\""NetworkManager-ibft"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ -DTEST_IBFT_DIR=\"$(abs_srcdir)\" \ -DTEST_SCRATCH_DIR=\"$(abs_builddir)/\" AM_LDFLAGS = \ $(GLIB_LIBS) \ - $(DBUS_LIBS) \ $(CODE_COVERAGE_LDFLAGS) noinst_PROGRAMS = test-ibft diff --git a/src/settings/plugins/ibft/tests/Makefile.in b/src/settings/plugins/ibft/tests/Makefile.in index 30bd78df..7ac2bdc1 100644 --- a/src/settings/plugins/ibft/tests/Makefile.in +++ b/src/settings/plugins/ibft/tests/Makefile.in @@ -405,7 +405,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -417,8 +416,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -428,6 +425,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -482,16 +480,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -528,6 +523,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -556,7 +553,6 @@ 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@ @@ -571,6 +567,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -631,6 +629,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -638,6 +637,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -656,8 +656,8 @@ with_valgrind = @with_valgrind@ @ENABLE_TESTS_TRUE@AM_CPPFLAGS = \ @ENABLE_TESTS_TRUE@ $(GLIB_CFLAGS) \ @ENABLE_TESTS_TRUE@ $(CODE_COVERAGE_CFLAGS) \ -@ENABLE_TESTS_TRUE@ -I$(top_srcdir)/include \ -@ENABLE_TESTS_TRUE@ -I$(top_builddir)/include \ +@ENABLE_TESTS_TRUE@ -I$(top_srcdir)/shared \ +@ENABLE_TESTS_TRUE@ -I$(top_builddir)/shared \ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/libnm-core \ @ENABLE_TESTS_TRUE@ -I$(top_builddir)/libnm-core \ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/src/ \ @@ -665,14 +665,13 @@ with_valgrind = @with_valgrind@ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/src/settings \ @ENABLE_TESTS_TRUE@ -I$(srcdir)/../ \ @ENABLE_TESTS_TRUE@ -DG_LOG_DOMAIN=\""NetworkManager-ibft"\" \ -@ENABLE_TESTS_TRUE@ -DNETWORKMANAGER_COMPILATION \ +@ENABLE_TESTS_TRUE@ -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ @ENABLE_TESTS_TRUE@ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ @ENABLE_TESTS_TRUE@ -DTEST_IBFT_DIR=\"$(abs_srcdir)\" \ @ENABLE_TESTS_TRUE@ -DTEST_SCRATCH_DIR=\"$(abs_builddir)/\" @ENABLE_TESTS_TRUE@AM_LDFLAGS = \ @ENABLE_TESTS_TRUE@ $(GLIB_LIBS) \ -@ENABLE_TESTS_TRUE@ $(DBUS_LIBS) \ @ENABLE_TESTS_TRUE@ $(CODE_COVERAGE_LDFLAGS) @ENABLE_TESTS_TRUE@test_ibft_SOURCES = \ diff --git a/src/settings/plugins/ibft/tests/test-ibft.c b/src/settings/plugins/ibft/tests/test-ibft.c index 980a9cee..c7aef050 100644 --- a/src/settings/plugins/ibft/tests/test-ibft.c +++ b/src/settings/plugins/ibft/tests/test-ibft.c @@ -33,7 +33,7 @@ #include "NetworkManagerUtils.h" #include "reader.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-test-utils.h" diff --git a/src/settings/plugins/ifcfg-rh/Makefile.am b/src/settings/plugins/ifcfg-rh/Makefile.am index 08ffa0ec..ab96a328 100644 --- a/src/settings/plugins/ifcfg-rh/Makefile.am +++ b/src/settings/plugins/ifcfg-rh/Makefile.am @@ -2,15 +2,31 @@ SUBDIRS = . tests @GNOME_CODE_COVERAGE_RULES@ -nm-ifcfg-rh-glue.h: nm-ifcfg-rh.xml - $(AM_V_GEN) dbus-binding-tool --prefix=nm_ifcfg_rh --mode=glib-server --output=$@ $< +# See note about gdbus-codegen in introspection/Makefile.am -BUILT_SOURCES = \ - nm-ifcfg-rh-glue.h +noinst_LTLIBRARIES = libnmdbus-ifcfg-rh.la + +nodist_libnmdbus_ifcfg_rh_la_SOURCES = \ + nmdbus-ifcfg-rh.c \ + nmdbus-ifcfg-rh.h + +libnmdbus_ifcfg_rh_la_CPPFLAGS = $(filter-out -DGLIB_VERSION_MAX_ALLOWED%,$(AM_CPPFLAGS)) + +nmdbus-ifcfg-rh.h: nm-ifcfg-rh.xml + $(AM_V_GEN) gdbus-codegen \ + --generate-c-code $(basename $@) \ + --c-namespace NMDBus \ + --interface-prefix com.redhat \ + $< + +nmdbus-ifcfg-rh.c: nmdbus-ifcfg-rh.h + @true + +BUILT_SOURCES = nmdbus-ifcfg-rh.h nmdbus-ifcfg-rh.c pkglib_LTLIBRARIES = libnm-settings-plugin-ifcfg-rh.la -noinst_LTLIBRARIES = libifcfg-rh-io.la +noinst_LTLIBRARIES += libifcfg-rh-io.la libifcfg_rh_io_la_SOURCES = \ shvar.c \ @@ -27,14 +43,13 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/ \ -I$(top_srcdir)/src/platform \ -I$(top_srcdir)/src/settings \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) \ $(NSS_CFLAGS) \ -DG_LOG_DOMAIN=\""NetworkManager-ifcfg-rh"\" \ -DSYSCONFDIR=\"$(sysconfdir)\" \ @@ -47,7 +62,7 @@ libnm_settings_plugin_ifcfg_rh_la_SOURCES = \ nm-ifcfg-connection.h libnm_settings_plugin_ifcfg_rh_la_LDFLAGS = -module -avoid-version -libnm_settings_plugin_ifcfg_rh_la_LIBADD = libifcfg-rh-io.la +libnm_settings_plugin_ifcfg_rh_la_LIBADD = libifcfg-rh-io.la libnmdbus-ifcfg-rh.la dbusservicedir = $(DBUS_SYS_DIR) dbusservice_DATA = nm-ifcfg-rh.conf diff --git a/src/settings/plugins/ifcfg-rh/Makefile.in b/src/settings/plugins/ifcfg-rh/Makefile.in index eaa456bb..3fc3495a 100644 --- a/src/settings/plugins/ifcfg-rh/Makefile.in +++ b/src/settings/plugins/ifcfg-rh/Makefile.in @@ -148,7 +148,8 @@ AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = -libnm_settings_plugin_ifcfg_rh_la_DEPENDENCIES = libifcfg-rh-io.la +libnm_settings_plugin_ifcfg_rh_la_DEPENDENCIES = libifcfg-rh-io.la \ + libnmdbus-ifcfg-rh.la am_libnm_settings_plugin_ifcfg_rh_la_OBJECTS = plugin.lo \ nm-ifcfg-connection.lo libnm_settings_plugin_ifcfg_rh_la_OBJECTS = \ @@ -157,6 +158,11 @@ libnm_settings_plugin_ifcfg_rh_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(libnm_settings_plugin_ifcfg_rh_la_LDFLAGS) $(LDFLAGS) -o $@ +libnmdbus_ifcfg_rh_la_LIBADD = +nodist_libnmdbus_ifcfg_rh_la_OBJECTS = \ + libnmdbus_ifcfg_rh_la-nmdbus-ifcfg-rh.lo +libnmdbus_ifcfg_rh_la_OBJECTS = \ + $(nodist_libnmdbus_ifcfg_rh_la_OBJECTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -192,7 +198,8 @@ am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libifcfg_rh_io_la_SOURCES) \ - $(libnm_settings_plugin_ifcfg_rh_la_SOURCES) + $(libnm_settings_plugin_ifcfg_rh_la_SOURCES) \ + $(nodist_libnmdbus_ifcfg_rh_la_SOURCES) DIST_SOURCES = $(libifcfg_rh_io_la_SOURCES) \ $(libnm_settings_plugin_ifcfg_rh_la_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ @@ -280,7 +287,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -292,8 +298,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -303,6 +307,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -357,16 +362,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -403,6 +405,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -431,7 +435,6 @@ 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@ @@ -446,6 +449,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -506,6 +511,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -513,6 +519,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -529,11 +536,16 @@ with_netconfig = @with_netconfig@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ SUBDIRS = . tests -BUILT_SOURCES = \ - nm-ifcfg-rh-glue.h +# See note about gdbus-codegen in introspection/Makefile.am +noinst_LTLIBRARIES = libnmdbus-ifcfg-rh.la libifcfg-rh-io.la +nodist_libnmdbus_ifcfg_rh_la_SOURCES = \ + nmdbus-ifcfg-rh.c \ + nmdbus-ifcfg-rh.h + +libnmdbus_ifcfg_rh_la_CPPFLAGS = $(filter-out -DGLIB_VERSION_MAX_ALLOWED%,$(AM_CPPFLAGS)) +BUILT_SOURCES = nmdbus-ifcfg-rh.h nmdbus-ifcfg-rh.c pkglib_LTLIBRARIES = libnm-settings-plugin-ifcfg-rh.la -noinst_LTLIBRARIES = libifcfg-rh-io.la libifcfg_rh_io_la_SOURCES = \ shvar.c \ shvar.h \ @@ -549,14 +561,13 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/ \ -I$(top_srcdir)/src/platform \ -I$(top_srcdir)/src/settings \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) \ $(NSS_CFLAGS) \ -DG_LOG_DOMAIN=\""NetworkManager-ifcfg-rh"\" \ -DSYSCONFDIR=\"$(sysconfdir)\" \ @@ -569,7 +580,7 @@ libnm_settings_plugin_ifcfg_rh_la_SOURCES = \ nm-ifcfg-connection.h libnm_settings_plugin_ifcfg_rh_la_LDFLAGS = -module -avoid-version -libnm_settings_plugin_ifcfg_rh_la_LIBADD = libifcfg-rh-io.la +libnm_settings_plugin_ifcfg_rh_la_LIBADD = libifcfg-rh-io.la libnmdbus-ifcfg-rh.la dbusservicedir = $(DBUS_SYS_DIR) dbusservice_DATA = nm-ifcfg-rh.conf EXTRA_DIST = \ @@ -664,12 +675,16 @@ libifcfg-rh-io.la: $(libifcfg_rh_io_la_OBJECTS) $(libifcfg_rh_io_la_DEPENDENCIES libnm-settings-plugin-ifcfg-rh.la: $(libnm_settings_plugin_ifcfg_rh_la_OBJECTS) $(libnm_settings_plugin_ifcfg_rh_la_DEPENDENCIES) $(EXTRA_libnm_settings_plugin_ifcfg_rh_la_DEPENDENCIES) $(AM_V_CCLD)$(libnm_settings_plugin_ifcfg_rh_la_LINK) -rpath $(pkglibdir) $(libnm_settings_plugin_ifcfg_rh_la_OBJECTS) $(libnm_settings_plugin_ifcfg_rh_la_LIBADD) $(LIBS) +libnmdbus-ifcfg-rh.la: $(libnmdbus_ifcfg_rh_la_OBJECTS) $(libnmdbus_ifcfg_rh_la_DEPENDENCIES) $(EXTRA_libnmdbus_ifcfg_rh_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libnmdbus_ifcfg_rh_la_OBJECTS) $(libnmdbus_ifcfg_rh_la_LIBADD) $(LIBS) + mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnmdbus_ifcfg_rh_la-nmdbus-ifcfg-rh.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nm-ifcfg-connection.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reader.Plo@am__quote@ @@ -698,6 +713,13 @@ distclean-compile: @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< +libnmdbus_ifcfg_rh_la-nmdbus-ifcfg-rh.lo: nmdbus-ifcfg-rh.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnmdbus_ifcfg_rh_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnmdbus_ifcfg_rh_la-nmdbus-ifcfg-rh.lo -MD -MP -MF $(DEPDIR)/libnmdbus_ifcfg_rh_la-nmdbus-ifcfg-rh.Tpo -c -o libnmdbus_ifcfg_rh_la-nmdbus-ifcfg-rh.lo `test -f 'nmdbus-ifcfg-rh.c' || echo '$(srcdir)/'`nmdbus-ifcfg-rh.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnmdbus_ifcfg_rh_la-nmdbus-ifcfg-rh.Tpo $(DEPDIR)/libnmdbus_ifcfg_rh_la-nmdbus-ifcfg-rh.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nmdbus-ifcfg-rh.c' object='libnmdbus_ifcfg_rh_la-nmdbus-ifcfg-rh.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnmdbus_ifcfg_rh_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnmdbus_ifcfg_rh_la-nmdbus-ifcfg-rh.lo `test -f 'nmdbus-ifcfg-rh.c' || echo '$(srcdir)/'`nmdbus-ifcfg-rh.c + mostlyclean-libtool: -rm -f *.lo @@ -1017,8 +1039,15 @@ uninstall-am: uninstall-dbusserviceDATA uninstall-pkglibLTLIBRARIES @GNOME_CODE_COVERAGE_RULES@ -nm-ifcfg-rh-glue.h: nm-ifcfg-rh.xml - $(AM_V_GEN) dbus-binding-tool --prefix=nm_ifcfg_rh --mode=glib-server --output=$@ $< +nmdbus-ifcfg-rh.h: nm-ifcfg-rh.xml + $(AM_V_GEN) gdbus-codegen \ + --generate-c-code $(basename $@) \ + --c-namespace NMDBus \ + --interface-prefix com.redhat \ + $< + +nmdbus-ifcfg-rh.c: nmdbus-ifcfg-rh.h + @true # 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. diff --git a/src/settings/plugins/ifcfg-rh/common.h b/src/settings/plugins/ifcfg-rh/common.h index 0ec355ee..5d6ebe6d 100644 --- a/src/settings/plugins/ifcfg-rh/common.h +++ b/src/settings/plugins/ifcfg-rh/common.h @@ -21,7 +21,7 @@ #ifndef __COMMON_H__ #define __COMMON_H__ -#include +#include "nm-default.h" #define IFCFG_TAG "ifcfg-" #define KEYS_TAG "keys-" diff --git a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c b/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c index 9499d8ce..336d9d66 100644 --- a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c +++ b/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c @@ -33,8 +33,9 @@ #include #include #include -#include -#include +#include "nm-platform.h" + +#include "nm-default.h" #include "common.h" #include "nm-config.h" @@ -107,7 +108,7 @@ devtimeout_ready (gpointer user_data) static void link_changed (NMPlatform *platform, NMPObjectType *obj_type, int ifindex, const NMPlatformLink *link, - NMPlatformSignalChangeType change_type, NMPlatformReason reason, + NMPlatformSignalChangeType change_type, NMConnection *self) { NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self); @@ -143,7 +144,7 @@ devtimeout_expired (gpointer user_data) nm_log_info (LOGD_SETTINGS, "Device for connection '%s' did not appear before timeout", nm_connection_get_id (NM_CONNECTION (self))); - g_signal_handler_disconnect (nm_platform_get (), priv->devtimeout_link_changed_handler); + g_signal_handler_disconnect (NM_PLATFORM_GET, priv->devtimeout_link_changed_handler); priv->devtimeout_link_changed_handler = 0; priv->devtimeout_timeout_id = 0; @@ -187,7 +188,7 @@ nm_ifcfg_connection_check_devtimeout (NMIfcfgConnection *self) devtimeout, ifname, nm_connection_get_id (NM_CONNECTION (self))); priv->devtimeout_link_changed_handler = - g_signal_connect (nm_platform_get (), NM_PLATFORM_SIGNAL_LINK_CHANGED, + g_signal_connect (NM_PLATFORM_GET, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (link_changed), self); priv->devtimeout_timeout_id = g_timeout_add_seconds (devtimeout, devtimeout_expired, self); } @@ -276,10 +277,7 @@ path_watch_stop (NMIfcfgConnection *self) ih = _get_inotify_helper (priv); - if (priv->ih_event_id) { - g_signal_handler_disconnect (ih, priv->ih_event_id); - priv->ih_event_id = 0; - } + nm_clear_g_signal_handler (ih, &priv->ih_event_id); if (priv->file_wd >= 0) { nm_inotify_helper_remove_watch (ih, priv->file_wd); @@ -380,6 +378,7 @@ replace_and_commit (NMSettingsConnection *connection, static void commit_changes (NMSettingsConnection *connection, + NMSettingsConnectionCommitReason commit_reason, NMSettingsConnectionCommitFunc callback, gpointer user_data) { @@ -407,7 +406,7 @@ commit_changes (NMSettingsConnection *connection, /* Don't bother writing anything out if in-memory and on-disk data are the same */ if (same) { /* But chain up to parent to handle success - emits updated signal */ - NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->commit_changes (connection, callback, user_data); + NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->commit_changes (connection, commit_reason, callback, user_data); return; } } @@ -430,7 +429,7 @@ commit_changes (NMSettingsConnection *connection, if (success) { /* Chain up to parent to handle success */ - NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->commit_changes (connection, callback, user_data); + NM_SETTINGS_CONNECTION_CLASS (nm_ifcfg_connection_parent_class)->commit_changes (connection, commit_reason, callback, user_data); } else { /* Otherwise immediate error */ callback (connection, error, user_data); @@ -514,15 +513,8 @@ dispose (GObject *object) path_watch_stop (NM_IFCFG_CONNECTION (object)); - if (priv->devtimeout_link_changed_handler) { - g_signal_handler_disconnect (nm_platform_get (), - priv->devtimeout_link_changed_handler); - priv->devtimeout_link_changed_handler = 0; - } - if (priv->devtimeout_timeout_id) { - g_source_remove (priv->devtimeout_timeout_id); - priv->devtimeout_timeout_id = 0; - } + nm_clear_g_signal_handler (NM_PLATFORM_GET, &priv->devtimeout_link_changed_handler); + nm_clear_g_source (&priv->devtimeout_timeout_id); g_clear_object (&priv->inotify_helper); diff --git a/src/settings/plugins/ifcfg-rh/nm-ifcfg-rh.conf b/src/settings/plugins/ifcfg-rh/nm-ifcfg-rh.conf index cade31dd..8fefaf18 100644 --- a/src/settings/plugins/ifcfg-rh/nm-ifcfg-rh.conf +++ b/src/settings/plugins/ifcfg-rh/nm-ifcfg-rh.conf @@ -7,7 +7,6 @@ - diff --git a/src/settings/plugins/ifcfg-rh/nm-ifcfg-rh.xml b/src/settings/plugins/ifcfg-rh/nm-ifcfg-rh.xml index 52793452..1f308dd4 100644 --- a/src/settings/plugins/ifcfg-rh/nm-ifcfg-rh.xml +++ b/src/settings/plugins/ifcfg-rh/nm-ifcfg-rh.xml @@ -10,7 +10,6 @@ Given an ifcfg file, return various internal information about it. - The full path to an ifcfg file. diff --git a/src/settings/plugins/ifcfg-rh/plugin.c b/src/settings/plugins/ifcfg-rh/plugin.c index 526cdafe..5afc46d6 100644 --- a/src/settings/plugins/ifcfg-rh/plugin.c +++ b/src/settings/plugins/ifcfg-rh/plugin.c @@ -30,39 +30,28 @@ #include #include -#include -#include -#include - -#include -#include -#include - -#if HAVE_SELINUX -#include -#endif #include "nm-setting-connection.h" +#include "nm-default.h" #include "common.h" -#include "nm-dbus-glib-types.h" #include "plugin.h" -#include "nm-system-config-interface.h" +#include "nm-settings-plugin.h" #include "nm-config.h" -#include "nm-logging.h" #include "NetworkManagerUtils.h" #include "nm-ifcfg-connection.h" -#include "nm-inotify-helper.h" #include "shvar.h" #include "reader.h" #include "writer.h" #include "utils.h" -#include "gsystem-local-alloc.h" +#include "nm-dbus-compat.h" +#include "nm-exported-object.h" -#define DBUS_SERVICE_NAME "com.redhat.ifcfgrh1" -#define DBUS_OBJECT_PATH "/com/redhat/ifcfgrh1" +#include "nmdbus-ifcfg-rh.h" +#define IFCFGRH1_DBUS_SERVICE_NAME "com.redhat.ifcfgrh1" +#define IFCFGRH1_DBUS_OBJECT_PATH "/com/redhat/ifcfgrh1" #define _NMLOG_DOMAIN LOGD_SETTINGS #define _NMLOG(level, ...) \ @@ -76,15 +65,7 @@ #define ERR_GET_MSG(err) (((err) && (err)->message) ? (err)->message : "(unknown)") -static gboolean impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin, - const char *in_ifcfg, - const char **out_uuid, - const char **out_path, - GError **error); - -#include "nm-ifcfg-rh-glue.h" - -static NMIfcfgConnection *update_connection (SCPluginIfcfg *plugin, +static NMIfcfgConnection *update_connection (SettingsPluginIfcfg *plugin, NMConnection *source, const char *full_path, NMIfcfgConnection *connection, @@ -92,37 +73,40 @@ static NMIfcfgConnection *update_connection (SCPluginIfcfg *plugin, GHashTable *protected_connections, GError **error); -static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class); +static void settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface); -G_DEFINE_TYPE_EXTENDED (SCPluginIfcfg, sc_plugin_ifcfg, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, - system_config_interface_init)) +G_DEFINE_TYPE_EXTENDED (SettingsPluginIfcfg, settings_plugin_ifcfg, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN, + settings_plugin_interface_init)) -#define SC_PLUGIN_IFCFG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfgPrivate)) +#define SETTINGS_PLUGIN_IFCFG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SETTINGS_TYPE_PLUGIN_IFCFG, SettingsPluginIfcfgPrivate)) typedef struct { - GHashTable *connections; /* uuid::connection */ + NMConfig *config; + + struct { + GDBusConnection *connection; + GDBusInterfaceSkeleton *interface; + GCancellable *cancellable; + gulong signal_id; + } dbus; + GHashTable *connections; /* uuid::connection */ gboolean initialized; - gulong ih_event_id; - int sc_network_wd; - GFileMonitor *hostname_monitor; - guint hostname_monitor_id; - char *hostname; GFileMonitor *ifcfg_monitor; - guint ifcfg_monitor_id; - - DBusGConnection *bus; -} SCPluginIfcfgPrivate; + gulong ifcfg_monitor_id; +} SettingsPluginIfcfgPrivate; +static SettingsPluginIfcfg *settings_plugin_ifcfg_get (void); +NM_DEFINE_SINGLETON_GETTER (SettingsPluginIfcfg, settings_plugin_ifcfg_get, SETTINGS_TYPE_PLUGIN_IFCFG); static void connection_ifcfg_changed (NMIfcfgConnection *connection, gpointer user_data) { - SCPluginIfcfg *self = SC_PLUGIN_IFCFG (user_data); - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); + SettingsPluginIfcfg *self = SETTINGS_PLUGIN_IFCFG (user_data); + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); const char *path; path = nm_settings_connection_get_filename (NM_SETTINGS_CONNECTION (connection)); @@ -142,14 +126,14 @@ connection_ifcfg_changed (NMIfcfgConnection *connection, gpointer user_data) static void connection_removed_cb (NMSettingsConnection *obj, gpointer user_data) { - g_hash_table_remove (SC_PLUGIN_IFCFG_GET_PRIVATE (user_data)->connections, + g_hash_table_remove (SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (user_data)->connections, nm_connection_get_uuid (NM_CONNECTION (obj))); } static void -remove_connection (SCPluginIfcfg *self, NMIfcfgConnection *connection) +remove_connection (SettingsPluginIfcfg *self, NMIfcfgConnection *connection) { - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); gboolean unmanaged, unrecognized; g_return_if_fail (self != NULL); @@ -168,15 +152,15 @@ remove_connection (SCPluginIfcfg *self, NMIfcfgConnection *connection) /* Emit changes _after_ removing the connection */ if (unmanaged) - g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); if (unrecognized) - g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED); + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNRECOGNIZED_SPECS_CHANGED); } static NMIfcfgConnection * -find_by_path (SCPluginIfcfg *self, const char *path) +find_by_path (SettingsPluginIfcfg *self, const char *path) { - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); GHashTableIter iter; NMSettingsConnection *candidate = NULL; @@ -191,7 +175,7 @@ find_by_path (SCPluginIfcfg *self, const char *path) } static NMIfcfgConnection * -update_connection (SCPluginIfcfg *self, +update_connection (SettingsPluginIfcfg *self, NMConnection *source, const char *full_path, NMIfcfgConnection *connection, @@ -199,7 +183,7 @@ update_connection (SCPluginIfcfg *self, GHashTable *protected_connections, GError **error) { - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self); + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); NMIfcfgConnection *connection_new; NMIfcfgConnection *connection_by_uuid; GError *local = NULL; @@ -346,18 +330,18 @@ update_connection (SCPluginIfcfg *self, if (old_unmanaged /* && !new_unmanaged */) { _LOGI ("Managing connection "NM_IFCFG_CONNECTION_LOG_FMT" and its device because NM_CONTROLLED was true.", NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); - g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection_by_uuid); + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, connection_by_uuid); } else if (old_unrecognized /* && !new_unrecognized */) { _LOGI ("Managing connection "NM_IFCFG_CONNECTION_LOG_FMT" because it is now a recognized type.", NM_IFCFG_CONNECTION_LOG_ARG (connection_new)); - g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection_by_uuid); + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, connection_by_uuid); } } if (unmanaged_changed) - g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); if (unrecognized_changed) - g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED); + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNRECOGNIZED_SPECS_CHANGED); } nm_settings_connection_set_filename (NM_SETTINGS_CONNECTION (connection_by_uuid), full_path); g_object_unref (connection_new); @@ -401,11 +385,11 @@ update_connection (SCPluginIfcfg *self, /* Only raise the signal if we were called without source, i.e. if we read the connection from file. * Otherwise, we were called by add_connection() which does not expect the signal. */ if (nm_ifcfg_connection_get_unmanaged_spec (connection_new)) - g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); else if (nm_ifcfg_connection_get_unrecognized_spec (connection_new)) - g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNRECOGNIZED_SPECS_CHANGED); + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNRECOGNIZED_SPECS_CHANGED); else - g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection_new); + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, connection_new); } return connection_new; } @@ -418,7 +402,7 @@ ifcfg_dir_changed (GFileMonitor *monitor, GFileMonitorEvent event_type, gpointer user_data) { - SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data); + SettingsPluginIfcfg *plugin = SETTINGS_PLUGIN_IFCFG (user_data); char *path, *ifcfg_path; NMIfcfgConnection *connection; @@ -447,9 +431,9 @@ ifcfg_dir_changed (GFileMonitor *monitor, } static void -setup_ifcfg_monitoring (SCPluginIfcfg *plugin) +setup_ifcfg_monitoring (SettingsPluginIfcfg *plugin) { - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (plugin); GFile *file; GFileMonitor *monitor; @@ -502,9 +486,9 @@ _sort_paths (const char **f1, const char **f2, GHashTable *paths) } static void -read_connections (SCPluginIfcfg *plugin) +read_connections (SettingsPluginIfcfg *plugin) { - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (plugin); GDir *dir; GError *err = NULL; const char *item; @@ -574,10 +558,10 @@ read_connections (SCPluginIfcfg *plugin) } static GSList * -get_connections (NMSystemConfigInterface *config) +get_connections (NMSettingsPlugin *config) { - SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config); - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + SettingsPluginIfcfg *plugin = SETTINGS_PLUGIN_IFCFG (config); + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (plugin); GSList *list = NULL; GHashTableIter iter; NMIfcfgConnection *connection; @@ -600,10 +584,10 @@ get_connections (NMSystemConfigInterface *config) } static gboolean -load_connection (NMSystemConfigInterface *config, +load_connection (NMSettingsPlugin *config, const char *filename) { - SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config); + SettingsPluginIfcfg *plugin = SETTINGS_PLUGIN_IFCFG (config); NMIfcfgConnection *connection; int dir_len = strlen (IFCFG_DIR); char *ifcfg_path; @@ -629,18 +613,18 @@ load_connection (NMSystemConfigInterface *config, } static void -reload_connections (NMSystemConfigInterface *config) +reload_connections (NMSettingsPlugin *config) { - SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config); + SettingsPluginIfcfg *plugin = SETTINGS_PLUGIN_IFCFG (config); read_connections (plugin); } static GSList * -get_unhandled_specs (NMSystemConfigInterface *config, +get_unhandled_specs (NMSettingsPlugin *config, const char *property) { - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config); + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (config); GSList *list = NULL, *list_iter; GHashTableIter iter; gpointer connection; @@ -668,24 +652,24 @@ get_unhandled_specs (NMSystemConfigInterface *config, } static GSList * -get_unmanaged_specs (NMSystemConfigInterface *config) +get_unmanaged_specs (NMSettingsPlugin *config) { return get_unhandled_specs (config, NM_IFCFG_CONNECTION_UNMANAGED_SPEC); } static GSList * -get_unrecognized_specs (NMSystemConfigInterface *config) +get_unrecognized_specs (NMSettingsPlugin *config) { return get_unhandled_specs (config, NM_IFCFG_CONNECTION_UNRECOGNIZED_SPEC); } static NMSettingsConnection * -add_connection (NMSystemConfigInterface *config, +add_connection (NMSettingsPlugin *config, NMConnection *connection, gboolean save_to_disk, GError **error) { - SCPluginIfcfg *self = SC_PLUGIN_IFCFG (config); + SettingsPluginIfcfg *self = SETTINGS_PLUGIN_IFCFG (config); gs_free char *path = NULL; /* Ensure we reject attempts to add the connection long before we're @@ -701,312 +685,316 @@ add_connection (NMSystemConfigInterface *config, return NM_SETTINGS_CONNECTION (update_connection (self, connection, path, NULL, FALSE, NULL, error)); } -#define SC_NETWORK_FILE "/etc/sysconfig/network" -#define HOSTNAME_FILE "/etc/hostname" - -static char * -plugin_get_hostname (SCPluginIfcfg *plugin) +static void +impl_ifcfgrh_get_ifcfg_details (SettingsPluginIfcfg *plugin, + GDBusMethodInvocation *context, + const char *in_ifcfg) { - shvarFile *network; - char *hostname; - gboolean ignore_localhost; + NMIfcfgConnection *connection; + NMSettingConnection *s_con; + const char *uuid; + const char *path; + gs_free char *ifcfg_path = NULL; - if (g_file_get_contents (HOSTNAME_FILE, &hostname, NULL, NULL)) { - g_strchomp (hostname); - return hostname; + if (!g_path_is_absolute (in_ifcfg)) { + g_dbus_method_invocation_return_error (context, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_CONNECTION, + "ifcfg path '%s' is not absolute", in_ifcfg); + return; } - network = svOpenFile (SC_NETWORK_FILE, NULL); - if (!network) { - _LOGW ("Could not get hostname: failed to read " SC_NETWORK_FILE); - return NULL; + ifcfg_path = utils_detect_ifcfg_path (in_ifcfg, TRUE); + if (!ifcfg_path) { + g_dbus_method_invocation_return_error (context, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_CONNECTION, + "ifcfg path '%s' is not an ifcfg base file", in_ifcfg); + return; } - hostname = svGetValue (network, "HOSTNAME", FALSE); - ignore_localhost = svTrueValue (network, "NM_IGNORE_HOSTNAME_LOCALHOST", FALSE); - if (ignore_localhost) { - /* Ignore a default hostname ('localhost[6]' or 'localhost[6].localdomain[6]') - * to preserve 'network' service behavior. - */ - if (hostname && !nm_utils_is_specific_hostname (hostname)) { - g_free (hostname); - hostname = NULL; - } + connection = find_by_path (plugin, ifcfg_path); + if ( !connection + || nm_ifcfg_connection_get_unmanaged_spec (connection) + || nm_ifcfg_connection_get_unrecognized_spec (connection)) { + g_dbus_method_invocation_return_error (context, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_INVALID_CONNECTION, + "ifcfg file '%s' unknown", in_ifcfg); + return; } - svCloseFile (network); - return hostname; -} - -static gboolean -plugin_set_hostname (SCPluginIfcfg *plugin, const char *hostname) -{ - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); - shvarFile *network; - char *hostname_eol; - gboolean ret; -#if HAVE_SELINUX - security_context_t se_ctx_prev = NULL, se_ctx = NULL; - struct stat file_stat = { .st_mode = 0 }; - mode_t st_mode = 0; - - /* Get default context for HOSTNAME_FILE and set it for fscreate */ - if (stat (HOSTNAME_FILE, &file_stat) == 0) - st_mode = file_stat.st_mode; - matchpathcon (HOSTNAME_FILE, st_mode, &se_ctx); - matchpathcon_fini (); - getfscreatecon (&se_ctx_prev); - setfscreatecon (se_ctx); -#endif - - hostname_eol = g_strdup_printf ("%s\n", hostname); - ret = g_file_set_contents (HOSTNAME_FILE, hostname_eol, -1, NULL); - -#if HAVE_SELINUX - /* Restore previous context and cleanup */ - setfscreatecon (se_ctx_prev); - freecon (se_ctx); - freecon (se_ctx_prev); -#endif - - if (!ret) { - _LOGW ("Could not save hostname: failed to create/open " HOSTNAME_FILE); - g_free (hostname_eol); - return FALSE; + s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); + if (!s_con) { + g_dbus_method_invocation_return_error (context, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_FAILED, + "unable to retrieve the connection setting"); + return; } - g_free (priv->hostname); - priv->hostname = g_strdup (hostname); - g_free (hostname_eol); + uuid = nm_setting_connection_get_uuid (s_con); + if (!uuid) { + g_dbus_method_invocation_return_error (context, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_FAILED, + "unable to get the UUID"); + return; + } - /* Remove "HOSTNAME" from SC_NETWORK_FILE, if present */ - network = svOpenFile (SC_NETWORK_FILE, NULL); - if (network) { - svSetValue (network, "HOSTNAME", NULL, FALSE); - svWriteFile (network, 0644, NULL); - svCloseFile (network); + path = nm_connection_get_path (NM_CONNECTION (connection)); + if (!path) { + g_dbus_method_invocation_return_error (context, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_FAILED, + "unable to get the connection D-Bus path"); + return; } - return TRUE; + g_dbus_method_invocation_return_value (context, + g_variant_new ("(so)", uuid, path)); } -static void -hostname_maybe_changed (SCPluginIfcfg *plugin) -{ - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); - char *new_hostname; - - new_hostname = plugin_get_hostname (plugin); - if ( (new_hostname && !priv->hostname) - || (!new_hostname && priv->hostname) - || (priv->hostname && new_hostname && strcmp (priv->hostname, new_hostname))) { - g_free (priv->hostname); - priv->hostname = new_hostname; - g_object_notify (G_OBJECT (plugin), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); - } else - g_free (new_hostname); -} +/*****************************************************************************/ static void -sc_network_changed_cb (NMInotifyHelper *ih, - struct inotify_event *evt, - const char *path, - gpointer user_data) +_dbus_clear (SettingsPluginIfcfg *self) { - SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data); - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); - if (evt->wd != priv->sc_network_wd) - return; + nm_clear_g_signal_handler (priv->dbus.connection, &priv->dbus.signal_id); + + nm_clear_g_cancellable (&priv->dbus.cancellable); + + if (priv->dbus.interface) { + g_dbus_interface_skeleton_unexport (priv->dbus.interface); + nm_exported_object_skeleton_release (priv->dbus.interface); + priv->dbus.interface = NULL; + } - hostname_maybe_changed (plugin); + g_clear_object (&priv->dbus.connection); } static void -hostname_changed_cb (GFileMonitor *monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer user_data) +_dbus_connection_closed (GDBusConnection *connection, + gboolean remote_peer_vanished, + GError *error, + gpointer user_data) { - SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (user_data); + _LOGW ("dbus: %s bus closed", IFCFGRH1_DBUS_SERVICE_NAME); + _dbus_clear (SETTINGS_PLUGIN_IFCFG (user_data)); - hostname_maybe_changed (plugin); + /* Retry or recover? */ } -static gboolean -impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin, - const char *in_ifcfg, - const char **out_uuid, - const char **out_path, - GError **error) +static void +_dbus_request_name_done (GObject *source_object, + GAsyncResult *res, + gpointer user_data) { - NMIfcfgConnection *connection; - NMSettingConnection *s_con; - const char *uuid; - const char *path; + GDBusConnection *connection = G_DBUS_CONNECTION (source_object); + SettingsPluginIfcfg *self; + SettingsPluginIfcfgPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *ret = NULL; + guint32 result; + + ret = g_dbus_connection_call_finish (connection, res, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; - if (!g_path_is_absolute (in_ifcfg)) { - g_set_error (error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_INVALID_CONNECTION, - "ifcfg path '%s' is not absolute", in_ifcfg); - return FALSE; - } + self = SETTINGS_PLUGIN_IFCFG (user_data); + priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); - connection = find_by_path (plugin, in_ifcfg); - if ( !connection - || nm_ifcfg_connection_get_unmanaged_spec (connection) - || nm_ifcfg_connection_get_unrecognized_spec (connection)) { - g_set_error (error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_INVALID_CONNECTION, - "ifcfg file '%s' unknown", in_ifcfg); - return FALSE; - } + g_clear_object (&priv->dbus.cancellable); - s_con = nm_connection_get_setting_connection (NM_CONNECTION (connection)); - if (!s_con) { - g_set_error (error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_FAILED, - "unable to retrieve the connection setting"); - return FALSE; + if (!ret) { + _LOGW ("dbus: couldn't acquire D-Bus service: %s", error->message); + _dbus_clear (self); + return; } - uuid = nm_setting_connection_get_uuid (s_con); - if (!uuid) { - g_set_error (error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_FAILED, - "unable to get the UUID"); - return FALSE; - } - - path = nm_connection_get_path (NM_CONNECTION (connection)); - if (!path) { - g_set_error (error, - NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_FAILED, - "unable to get the connection D-Bus path"); - return FALSE; + g_variant_get (ret, "(u)", &result); + + if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + _LOGW ("dbus: couldn't acquire ifcfgrh1 D-Bus service (already taken)"); + _dbus_clear (self); + return; } - *out_uuid = g_strdup (uuid); - *out_path = g_strdup (path); + { + GType skeleton_type = NMDBUS_TYPE_IFCFGRH1_SKELETON; + gs_free char *method_name_get_ifcfg_details = NULL; + NMExportedObjectDBusMethodImpl methods[] = { + { + .method_name = (method_name_get_ifcfg_details = nm_exported_object_skeletonify_method_name ("GetIfcfgDetails")), + .impl = G_CALLBACK (impl_ifcfgrh_get_ifcfg_details), + }, + }; + + priv->dbus.interface = nm_exported_object_skeleton_create (skeleton_type, + g_type_class_peek (SETTINGS_TYPE_PLUGIN_IFCFG), + methods, + G_N_ELEMENTS (methods), + (GObject *) self); + + if (!g_dbus_interface_skeleton_export (priv->dbus.interface, + priv->dbus.connection, + IFCFGRH1_DBUS_OBJECT_PATH, + &error)) { + nm_exported_object_skeleton_release (priv->dbus.interface); + priv->dbus.interface = NULL; + _LOGW ("dbus: failed exporting interface: %s", error->message); + _dbus_clear (self); + return; + } + } - return TRUE; + _LOGD ("dbus: aquired D-Bus service %s and exported %s object", + IFCFGRH1_DBUS_SERVICE_NAME, + IFCFGRH1_DBUS_OBJECT_PATH); } static void -init (NMSystemConfigInterface *config) +_dbus_create_done (GObject *source_object, + GAsyncResult *res, + gpointer user_data) { + SettingsPluginIfcfg *self; + SettingsPluginIfcfgPrivate *priv; + gs_free_error GError *error = NULL; + GDBusConnection *connection; + + connection = g_dbus_connection_new_for_address_finish (res, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = SETTINGS_PLUGIN_IFCFG (user_data); + priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); + + g_clear_object (&priv->dbus.cancellable); + + if (!connection) { + _LOGW ("dbus: couldn't initialize system bus: %s", error->message); + return; + } + + priv->dbus.connection = connection; + priv->dbus.cancellable = g_cancellable_new (); + + priv->dbus.signal_id = g_signal_connect (priv->dbus.connection, + "closed", + G_CALLBACK (_dbus_connection_closed), + self); + + g_dbus_connection_call (priv->dbus.connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "RequestName", + g_variant_new ("(su)", + IFCFGRH1_DBUS_SERVICE_NAME, + DBUS_NAME_FLAG_DO_NOT_QUEUE), + G_VARIANT_TYPE ("(u)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->dbus.cancellable, + _dbus_request_name_done, + self); } static void -sc_plugin_ifcfg_init (SCPluginIfcfg *plugin) +_dbus_setup (SettingsPluginIfcfg *self) { - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); - NMInotifyHelper *ih; - GError *error = NULL; - gboolean success = FALSE; - GFile *file; - GFileMonitor *monitor; - - priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); + gs_free char *address = NULL; + gs_free_error GError *error = NULL; - /* We watch SC_NETWORK_FILE via NMInotifyHelper (which doesn't track file creation but - * *does* track modifications made via other hard links), since we expect it to always - * exist. But we watch HOSTNAME_FILE via GFileMonitor (which has the opposite - * semantics), since /etc/hostname might not exist, but is unlikely to have hard - * links. bgo 532815 is the bug for being able to just use GFileMonitor for both. - */ - - ih = nm_inotify_helper_get (); - priv->ih_event_id = g_signal_connect (ih, "event", G_CALLBACK (sc_network_changed_cb), plugin); - priv->sc_network_wd = nm_inotify_helper_add_watch (ih, SC_NETWORK_FILE); + g_return_if_fail (!priv->dbus.connection); - file = g_file_new_for_path (HOSTNAME_FILE); - monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); - g_object_unref (file); - if (monitor) { - priv->hostname_monitor_id = - g_signal_connect (monitor, "changed", G_CALLBACK (hostname_changed_cb), plugin); - priv->hostname_monitor = monitor; + address = g_dbus_address_get_for_bus_sync (G_BUS_TYPE_SYSTEM, NULL, &error); + if (address == NULL) { + _LOGW ("dbus: failed getting address for system bus: %s", error->message); + return; } - priv->hostname = plugin_get_hostname (plugin); + priv->dbus.cancellable = g_cancellable_new (); - priv->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); - if (!priv->bus) { - _LOGW ("Couldn't connect to D-Bus: %s", error->message); - g_clear_error (&error); - } else { - DBusConnection *tmp; - DBusGProxy *proxy; - int result; - - tmp = dbus_g_connection_get_connection (priv->bus); - dbus_connection_set_exit_on_disconnect (tmp, FALSE); - - proxy = dbus_g_proxy_new_for_name (priv->bus, - "org.freedesktop.DBus", - "/org/freedesktop/DBus", - "org.freedesktop.DBus"); - - if (!dbus_g_proxy_call (proxy, "RequestName", &error, - G_TYPE_STRING, DBUS_SERVICE_NAME, - G_TYPE_UINT, DBUS_NAME_FLAG_DO_NOT_QUEUE, - G_TYPE_INVALID, - G_TYPE_UINT, &result, - G_TYPE_INVALID)) { - _LOGW ("Couldn't acquire D-Bus service: %s", error->message); - g_clear_error (&error); - } else if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { - _LOGW ("Couldn't acquire ifcfgrh1 D-Bus service (already taken)"); - } else - success = TRUE; - } + g_dbus_connection_new_for_address (address, + G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT + | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, + NULL, + priv->dbus.cancellable, + _dbus_create_done, + self); +} - if (!success) { - if (priv->bus) { - dbus_g_connection_unref (priv->bus); - priv->bus = NULL; - } +static void +config_changed_cb (NMConfig *config, + NMConfigData *config_data, + NMConfigChangeFlags changes, + NMConfigData *old_data, + SettingsPluginIfcfg *self) +{ + /* If the dbus connection for some reason is borked the D-Bus service + * won't be offered. + * + * On SIGHUP and SIGUSR1 try to re-connect to D-Bus. So in the unlikely + * event that the D-Bus conneciton is broken, that allows for recovery + * without need for restarting NetworkManager. */ + if ( NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_SIGHUP) + || NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_SIGUSR1)) { + if (!SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self)->dbus.connection) + _dbus_setup (self); } } +/*****************************************************************************/ + static void -dispose (GObject *object) +init (NMSettingsPlugin *config) { - SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (object); - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); - NMInotifyHelper *ih; +} - if (priv->bus) { - dbus_g_connection_unref (priv->bus); - priv->bus = NULL; - } +static void +settings_plugin_ifcfg_init (SettingsPluginIfcfg *plugin) +{ + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (plugin); + + priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); +} - if (priv->ih_event_id) { - ih = nm_inotify_helper_get (); +static void +constructed (GObject *object) +{ + SettingsPluginIfcfg *self = SETTINGS_PLUGIN_IFCFG (object); + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); - g_signal_handler_disconnect (ih, priv->ih_event_id); - priv->ih_event_id = 0; + G_OBJECT_CLASS (settings_plugin_ifcfg_parent_class)->constructed (object); - if (priv->sc_network_wd >= 0) - nm_inotify_helper_remove_watch (ih, priv->sc_network_wd); - } + priv->config = nm_config_get (); + g_object_add_weak_pointer ((GObject *) priv->config, (gpointer *) &priv->config); + g_signal_connect (priv->config, + NM_CONFIG_SIGNAL_CONFIG_CHANGED, + G_CALLBACK (config_changed_cb), + self); - if (priv->hostname_monitor) { - if (priv->hostname_monitor_id) - g_signal_handler_disconnect (priv->hostname_monitor, priv->hostname_monitor_id); + _dbus_setup (self); +} + +static void +dispose (GObject *object) +{ + SettingsPluginIfcfg *self = SETTINGS_PLUGIN_IFCFG (object); + SettingsPluginIfcfgPrivate *priv = SETTINGS_PLUGIN_IFCFG_GET_PRIVATE (self); - g_file_monitor_cancel (priv->hostname_monitor); - g_object_unref (priv->hostname_monitor); + if (priv->config) { + g_object_remove_weak_pointer ((GObject *) priv->config, (gpointer *) &priv->config); + g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self); + priv->config = NULL; } - g_free (priv->hostname); + _dbus_clear (self); if (priv->connections) { g_hash_table_destroy (priv->connections); @@ -1021,27 +1009,22 @@ dispose (GObject *object) g_object_unref (priv->ifcfg_monitor); } - G_OBJECT_CLASS (sc_plugin_ifcfg_parent_class)->dispose (object); + G_OBJECT_CLASS (settings_plugin_ifcfg_parent_class)->dispose (object); } static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (object); - switch (prop_id) { - case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME: + case NM_SETTINGS_PLUGIN_PROP_NAME: g_value_set_string (value, IFCFG_PLUGIN_NAME); break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO: + case NM_SETTINGS_PLUGIN_PROP_INFO: g_value_set_string (value, IFCFG_PLUGIN_INFO); break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES: - g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS | NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME); - break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME: - g_value_set_string (value, priv->hostname); + case NM_SETTINGS_PLUGIN_PROP_CAPABILITIES: + g_value_set_uint (value, NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1053,15 +1036,7 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - const char *hostname; - switch (prop_id) { - case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME: - hostname = g_value_get_string (value); - if (hostname && strlen (hostname) < 1) - hostname = NULL; - plugin_set_hostname (SC_PLUGIN_IFCFG (object), hostname); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1069,65 +1044,45 @@ set_property (GObject *object, guint prop_id, } static void -sc_plugin_ifcfg_class_init (SCPluginIfcfgClass *req_class) +settings_plugin_ifcfg_class_init (SettingsPluginIfcfgClass *req_class) { GObjectClass *object_class = G_OBJECT_CLASS (req_class); - g_type_class_add_private (req_class, sizeof (SCPluginIfcfgPrivate)); + g_type_class_add_private (req_class, sizeof (SettingsPluginIfcfgPrivate)); + object_class->constructed = constructed; object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME, - NM_SYSTEM_CONFIG_INTERFACE_NAME); - - g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, - NM_SYSTEM_CONFIG_INTERFACE_INFO); + NM_SETTINGS_PLUGIN_PROP_NAME, + NM_SETTINGS_PLUGIN_NAME); g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES, - NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES); + NM_SETTINGS_PLUGIN_PROP_INFO, + NM_SETTINGS_PLUGIN_INFO); g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME, - NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); - - dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (req_class), - &dbus_glib_nm_ifcfg_rh_object_info); + NM_SETTINGS_PLUGIN_PROP_CAPABILITIES, + NM_SETTINGS_PLUGIN_CAPABILITIES); } static void -system_config_interface_init (NMSystemConfigInterface *system_config_interface_class) +settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) { /* interface implementation */ - system_config_interface_class->get_connections = get_connections; - system_config_interface_class->add_connection = add_connection; - system_config_interface_class->load_connection = load_connection; - system_config_interface_class->reload_connections = reload_connections; - system_config_interface_class->get_unmanaged_specs = get_unmanaged_specs; - system_config_interface_class->get_unrecognized_specs = get_unrecognized_specs; - system_config_interface_class->init = init; + plugin_iface->get_connections = get_connections; + plugin_iface->add_connection = add_connection; + plugin_iface->load_connection = load_connection; + plugin_iface->reload_connections = reload_connections; + plugin_iface->get_unmanaged_specs = get_unmanaged_specs; + plugin_iface->get_unrecognized_specs = get_unrecognized_specs; + plugin_iface->init = init; } G_MODULE_EXPORT GObject * -nm_system_config_factory (void) +nm_settings_plugin_factory (void) { - static SCPluginIfcfg *singleton = NULL; - SCPluginIfcfgPrivate *priv; - - if (!singleton) { - singleton = SC_PLUGIN_IFCFG (g_object_new (SC_TYPE_PLUGIN_IFCFG, NULL)); - priv = SC_PLUGIN_IFCFG_GET_PRIVATE (singleton); - if (priv->bus) - dbus_g_connection_register_g_object (priv->bus, - DBUS_OBJECT_PATH, - G_OBJECT (singleton)); - _LOGD ("Acquired D-Bus service %s", DBUS_SERVICE_NAME); - } else - g_object_ref (singleton); - - return G_OBJECT (singleton); + return g_object_ref (settings_plugin_ifcfg_get ()); } diff --git a/src/settings/plugins/ifcfg-rh/plugin.h b/src/settings/plugins/ifcfg-rh/plugin.h index d37decfd..eba734cf 100644 --- a/src/settings/plugins/ifcfg-rh/plugin.h +++ b/src/settings/plugins/ifcfg-rh/plugin.h @@ -24,27 +24,27 @@ #ifndef _PLUGIN_H_ #define _PLUGIN_H_ -#include +#include "nm-exported-object.h" -#define SC_TYPE_PLUGIN_IFCFG (sc_plugin_ifcfg_get_type ()) -#define SC_PLUGIN_IFCFG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfg)) -#define SC_PLUGIN_IFCFG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfgClass)) -#define SC_IS_PLUGIN_IFCFG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_IFCFG)) -#define SC_IS_PLUGIN_IFCFG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_PLUGIN_IFCFG)) -#define SC_PLUGIN_IFCFG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfgClass)) +#define SETTINGS_TYPE_PLUGIN_IFCFG (settings_plugin_ifcfg_get_type ()) +#define SETTINGS_PLUGIN_IFCFG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SETTINGS_TYPE_PLUGIN_IFCFG, SettingsPluginIfcfg)) +#define SETTINGS_PLUGIN_IFCFG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SETTINGS_TYPE_PLUGIN_IFCFG, SettingsPluginIfcfgClass)) +#define SETTINGS_IS_PLUGIN_IFCFG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SETTINGS_TYPE_PLUGIN_IFCFG)) +#define SETTINGS_IS_PLUGIN_IFCFG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SETTINGS_TYPE_PLUGIN_IFCFG)) +#define SETTINGS_PLUGIN_IFCFG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SETTINGS_TYPE_PLUGIN_IFCFG, SettingsPluginIfcfgClass)) -typedef struct _SCPluginIfcfg SCPluginIfcfg; -typedef struct _SCPluginIfcfgClass SCPluginIfcfgClass; +typedef struct _SettingsPluginIfcfg SettingsPluginIfcfg; +typedef struct _SettingsPluginIfcfgClass SettingsPluginIfcfgClass; -struct _SCPluginIfcfg { +struct _SettingsPluginIfcfg { GObject parent; }; -struct _SCPluginIfcfgClass { +struct _SettingsPluginIfcfgClass { GObjectClass parent; }; -GType sc_plugin_ifcfg_get_type (void); +GType settings_plugin_ifcfg_get_type (void); #endif /* _PLUGIN_H_ */ diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c index 271b7bb1..bcb726aa 100644 --- a/src/settings/plugins/ifcfg-rh/reader.c +++ b/src/settings/plugins/ifcfg-rh/reader.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2008 - 2014 Red Hat, Inc. + * Copyright 2008 - 2015 Red Hat, Inc. */ #include "config.h" @@ -31,8 +31,6 @@ #include #include -#include -#include #include #include #include @@ -49,13 +47,12 @@ #include #include #include +#include "nm-default.h" #include "nm-core-internal.h" #include #include "nm-platform.h" #include "NetworkManagerUtils.h" -#include "nm-logging.h" -#include "gsystem-local-alloc.h" #include "common.h" #include "shvar.h" @@ -131,6 +128,7 @@ make_connection_setting (const char *file, const char *prefix) { NMSettingConnection *s_con; + NMSettingConnectionLldp lldp; const char *ifcfg_name = NULL; char *new_id, *uuid = NULL, *zone = NULL, *value; @@ -168,17 +166,25 @@ make_connection_setting (const char *file, g_free (value); } + value = svGetValue (ifcfg, "LLDP", FALSE); + if (!g_strcmp0 (value, "rx")) + lldp = NM_SETTING_CONNECTION_LLDP_ENABLE_RX; + else + lldp = svParseBoolean (value, NM_SETTING_CONNECTION_LLDP_DEFAULT); + g_free (value); + /* Missing ONBOOT is treated as "ONBOOT=true" by the old network service */ g_object_set (s_con, NM_SETTING_CONNECTION_AUTOCONNECT, - svTrueValue (ifcfg, "ONBOOT", TRUE), + svGetValueBoolean (ifcfg, "ONBOOT", TRUE), NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, (gint) svGetValueInt64 (ifcfg, "AUTOCONNECT_PRIORITY", 10, NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MIN, NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MAX, NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_DEFAULT), NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES, - svTrueValue (ifcfg, "AUTOCONNECT_SLAVES", NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT), + svGetValueBoolean (ifcfg, "AUTOCONNECT_SLAVES", NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES_DEFAULT), + NM_SETTING_CONNECTION_LLDP, lldp, NULL); value = svGetValue (ifcfg, "USERS", FALSE); @@ -250,7 +256,7 @@ make_connection_setting (const char *file, g_free (value); } - switch (svTrueValue (ifcfg, "CONNECTION_METERED", -1)) { + switch (svGetValueBoolean (ifcfg, "CONNECTION_METERED", -1)) { case TRUE: g_object_set (s_con, NM_SETTING_CONNECTION_METERED, NM_METERED_YES, NULL); break; @@ -274,8 +280,7 @@ read_ip4_address (shvarFile *ifcfg, g_return_val_if_fail (ifcfg != NULL, FALSE); g_return_val_if_fail (tag != NULL, FALSE); g_return_val_if_fail (out_addr != NULL, FALSE); - if (error) - g_return_val_if_fail (*error == NULL, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); *out_addr = NULL; @@ -363,8 +368,7 @@ read_full_ip4_address (shvarFile *ifcfg, g_return_val_if_fail (ifcfg != NULL, FALSE); g_return_val_if_fail (out_address != NULL, FALSE); g_return_val_if_fail (*out_address == NULL, FALSE); - if (error) - g_return_val_if_fail (*error == NULL, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); ip_tag = get_numbered_tag ("IPADDR", which); prefix_tag = get_numbered_tag ("PREFIX", which); @@ -462,8 +466,7 @@ read_one_ip4_route (shvarFile *ifcfg, g_return_val_if_fail (ifcfg != NULL, FALSE); g_return_val_if_fail (out_route != NULL, FALSE); g_return_val_if_fail (*out_route == NULL, FALSE); - if (error) - g_return_val_if_fail (*error == NULL, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); ip_tag = g_strdup_printf ("ADDRESS%u", which); netmask_tag = g_strdup_printf ("NETMASK%u", which); @@ -559,8 +562,7 @@ read_route_file_legacy (const char *filename, NMSettingIPConfig *s_ip4, GError * g_return_val_if_fail (filename != NULL, FALSE); g_return_val_if_fail (s_ip4 != NULL, FALSE); - if (error) - g_return_val_if_fail (*error == NULL, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); /* Read the route file */ if (!g_file_get_contents (filename, &contents, &len, NULL) || !len) { @@ -678,6 +680,32 @@ error: return success; } +static void +parse_dns_options (NMSettingIPConfig *ip_config, char *value) +{ + char **options = NULL; + + g_return_if_fail (ip_config); + + if (!value) + return; + + if (!nm_setting_ip_config_has_dns_options (ip_config)) + nm_setting_ip_config_clear_dns_options (ip_config, TRUE); + + options = g_strsplit (value, " ", 0); + if (options) { + char **item; + for (item = options; *item; item++) { + if (strlen (*item)) { + if (!nm_setting_ip_config_add_dns_option (ip_config, *item)) + PARSE_WARNING ("can't add DNS option '%s'", *item); + } + } + g_strfreev (options); + } +} + static gboolean parse_full_ip6_address (shvarFile *ifcfg, const char *addr_str, @@ -693,8 +721,7 @@ parse_full_ip6_address (shvarFile *ifcfg, g_return_val_if_fail (addr_str != NULL, FALSE); g_return_val_if_fail (out_address != NULL, FALSE); g_return_val_if_fail (*out_address == NULL, FALSE); - if (error) - g_return_val_if_fail (*error == NULL, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); /* Split the address and prefix */ list = g_strsplit_set (addr_str, "/", 2); @@ -758,8 +785,7 @@ read_route6_file (const char *filename, NMSettingIPConfig *s_ip6, GError **error g_return_val_if_fail (filename != NULL, FALSE); g_return_val_if_fail (s_ip6 != NULL, FALSE); - if (error) - g_return_val_if_fail (*error == NULL, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); /* Read the route file */ if (!g_file_get_contents (filename, &contents, &len, NULL) || !len) { @@ -892,6 +918,7 @@ make_ip4_setting (shvarFile *ifcfg, char *value = NULL; char *route_path = NULL; char *method; + char *dns_options = NULL; gs_free char *gateway = NULL; gint32 i; shvarFile *network_ifcfg; @@ -905,7 +932,7 @@ make_ip4_setting (shvarFile *ifcfg, * specified is DEFROUTE=yes which means that this connection can be used * as a default route */ - never_default = !svTrueValue (ifcfg, "DEFROUTE", TRUE); + never_default = !svGetValueBoolean (ifcfg, "DEFROUTE", TRUE); /* Then check if GATEWAYDEV; it's global and overrides DEFROUTE */ network_ifcfg = svOpenFile (network_file, NULL); @@ -915,6 +942,7 @@ make_ip4_setting (shvarFile *ifcfg, /* Get the connection ifcfg device name and the global gateway device */ value = svGetValue (ifcfg, "DEVICE", FALSE); gatewaydev = svGetValue (network_ifcfg, "GATEWAYDEV", FALSE); + dns_options = svGetValueFull (network_ifcfg, "RES_OPTIONS", FALSE); /* If there was a global gateway device specified, then only connections * for that device can be the default connection. @@ -979,10 +1007,10 @@ make_ip4_setting (shvarFile *ifcfg, g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, method, - NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, !svTrueValue (ifcfg, "PEERDNS", TRUE), - NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "PEERROUTES", TRUE), + NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, !svGetValueBoolean (ifcfg, "PEERDNS", TRUE), + NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, !svGetValueBoolean (ifcfg, "PEERROUTES", TRUE), NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default, - NM_SETTING_IP_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV4_FAILURE_FATAL", FALSE), + NM_SETTING_IP_CONFIG_MAY_FAIL, !svGetValueBoolean (ifcfg, "IPV4_FAILURE_FATAL", FALSE), NM_SETTING_IP_CONFIG_ROUTE_METRIC, svGetValueInt64 (ifcfg, "IPV4_ROUTE_METRIC", 10, -1, G_MAXUINT32, -1), NULL); @@ -993,13 +1021,22 @@ make_ip4_setting (shvarFile *ifcfg, /* Handle DHCP settings */ if (!strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO)) { value = svGetValue (ifcfg, "DHCP_HOSTNAME", FALSE); - if (value && strlen (value)) + if (value && *value) g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, value, NULL); g_free (value); + value = svGetValue (ifcfg, "DHCP_FQDN", FALSE); + if (value && *value) { + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_DHCP_HOSTNAME, NULL, + NM_SETTING_IP4_CONFIG_DHCP_FQDN, value, + NULL); + } + g_free (value); + g_object_set (s_ip4, - NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, - svTrueValue (ifcfg, "DHCP_SEND_HOSTNAME", TRUE), + NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME, svGetValueBoolean (ifcfg, "DHCP_SEND_HOSTNAME", TRUE), + NM_SETTING_IP4_CONFIG_DHCP_TIMEOUT, svGetValueInt64 (ifcfg, "IPV4_DHCP_TIMEOUT", 10, 0, G_MAXUINT32, 0), NULL); value = svGetValue (ifcfg, "DHCP_CLIENT_ID", FALSE); @@ -1101,6 +1138,14 @@ make_ip4_setting (shvarFile *ifcfg, g_free (value); } + /* DNS options */ + value = svGetValueFull (ifcfg, "RES_OPTIONS", FALSE); + parse_dns_options (s_ip4, value); + parse_dns_options (s_ip4, dns_options); + g_free (value); + g_free (dns_options); + dns_options = NULL; + /* Static routes - route- file */ route_path = utils_get_route_path (ifcfg->fileName); @@ -1157,6 +1202,7 @@ make_ip4_setting (shvarFile *ifcfg, return NM_SETTING (s_ip4); done: + g_free (dns_options); g_free (route_path); g_object_unref (s_ip4); return NULL; @@ -1271,6 +1317,7 @@ make_ip6_setting (shvarFile *ifcfg, char *value = NULL; char *str_value; char *route6_path = NULL; + char *dns_options = NULL; gboolean ipv6init, ipv6forwarding, ipv6_autoconf, dhcp6 = FALSE; char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; char *ipv6addr, *ipv6addr_secondaries; @@ -1279,8 +1326,9 @@ make_ip6_setting (shvarFile *ifcfg, shvarFile *network_ifcfg; gboolean never_default = FALSE; gboolean ip6_privacy = FALSE, ip6_privacy_prefer_public_ip; - char *ip6_privacy_str; NMSettingIP6ConfigPrivacy ip6_privacy_val; + NMSettingIP6ConfigAddrGenMode addr_gen_mode; + char *tmp; s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new (); @@ -1289,7 +1337,7 @@ make_ip6_setting (shvarFile *ifcfg, * specified is IPV6_DEFROUTE=yes which means that this connection can be used * as a default route */ - never_default = !svTrueValue (ifcfg, "IPV6_DEFROUTE", TRUE); + never_default = !svGetValueBoolean (ifcfg, "IPV6_DEFROUTE", TRUE); /* Then check if IPV6_DEFAULTGW or IPV6_DEFAULTDEV is specified; * they are global and override IPV6_DEFROUTE @@ -1304,6 +1352,7 @@ make_ip6_setting (shvarFile *ifcfg, value = svGetValue (ifcfg, "DEVICE", FALSE); ipv6_defaultgw = svGetValue (network_ifcfg, "IPV6_DEFAULTGW", FALSE); ipv6_defaultdev = svGetValue (network_ifcfg, "IPV6_DEFAULTDEV", FALSE); + dns_options = svGetValueFull (network_ifcfg, "RES_OPTIONS", FALSE); if (ipv6_defaultgw) { default_dev = strchr (ipv6_defaultgw, '%'); @@ -1328,11 +1377,11 @@ make_ip6_setting (shvarFile *ifcfg, /* Find out method property */ /* Is IPV6 enabled? Set method to "ignored", when not enabled */ str_value = svGetValue (ifcfg, "IPV6INIT", FALSE); - ipv6init = svTrueValue (ifcfg, "IPV6INIT", FALSE); + ipv6init = svGetValueBoolean (ifcfg, "IPV6INIT", FALSE); if (!str_value) { network_ifcfg = svOpenFile (network_file, NULL); if (network_ifcfg) { - ipv6init = svTrueValue (network_ifcfg, "IPV6INIT", FALSE); + ipv6init = svGetValueBoolean (network_ifcfg, "IPV6INIT", FALSE); svCloseFile (network_ifcfg); } } @@ -1341,9 +1390,9 @@ make_ip6_setting (shvarFile *ifcfg, if (!ipv6init) method = NM_SETTING_IP6_CONFIG_METHOD_IGNORE; /* IPv6 is disabled */ else { - ipv6forwarding = svTrueValue (ifcfg, "IPV6FORWARDING", FALSE); - ipv6_autoconf = svTrueValue (ifcfg, "IPV6_AUTOCONF", !ipv6forwarding); - dhcp6 = svTrueValue (ifcfg, "DHCPV6C", FALSE); + ipv6forwarding = svGetValueBoolean (ifcfg, "IPV6FORWARDING", FALSE); + ipv6_autoconf = svGetValueBoolean (ifcfg, "IPV6_AUTOCONF", !ipv6forwarding); + dhcp6 = svGetValueBoolean (ifcfg, "DHCPV6C", FALSE); if (ipv6_autoconf) method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; @@ -1363,27 +1412,27 @@ make_ip6_setting (shvarFile *ifcfg, /* TODO - handle other methods */ /* Read IPv6 Privacy Extensions configuration */ - ip6_privacy_str = svGetValue (ifcfg, "IPV6_PRIVACY", FALSE); - if (ip6_privacy_str) { - ip6_privacy = svTrueValue (ifcfg, "IPV6_PRIVACY", FALSE); + tmp = svGetValue (ifcfg, "IPV6_PRIVACY", FALSE); + if (tmp) { + ip6_privacy = svGetValueBoolean (ifcfg, "IPV6_PRIVACY", FALSE); if (!ip6_privacy) - ip6_privacy = g_strcmp0 (ip6_privacy_str, "rfc4941") == 0 || - g_strcmp0 (ip6_privacy_str, "rfc3041") == 0; + ip6_privacy = g_strcmp0 (tmp, "rfc4941") == 0 || + g_strcmp0 (tmp, "rfc3041") == 0; } - ip6_privacy_prefer_public_ip = svTrueValue (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", FALSE); - ip6_privacy_val = ip6_privacy_str ? + ip6_privacy_prefer_public_ip = svGetValueBoolean (ifcfg, "IPV6_PRIVACY_PREFER_PUBLIC_IP", FALSE); + ip6_privacy_val = tmp ? (ip6_privacy ? (ip6_privacy_prefer_public_ip ? NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR : NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR) : NM_SETTING_IP6_CONFIG_PRIVACY_DISABLED) : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; - g_free (ip6_privacy_str); + g_free (tmp); g_object_set (s_ip6, NM_SETTING_IP_CONFIG_METHOD, method, - NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, !svTrueValue (ifcfg, "IPV6_PEERDNS", TRUE), - NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, !svTrueValue (ifcfg, "IPV6_PEERROUTES", TRUE), + NM_SETTING_IP_CONFIG_IGNORE_AUTO_DNS, !svGetValueBoolean (ifcfg, "IPV6_PEERDNS", TRUE), + NM_SETTING_IP_CONFIG_IGNORE_AUTO_ROUTES, !svGetValueBoolean (ifcfg, "IPV6_PEERROUTES", TRUE), NM_SETTING_IP_CONFIG_NEVER_DEFAULT, never_default, - NM_SETTING_IP_CONFIG_MAY_FAIL, !svTrueValue (ifcfg, "IPV6_FAILURE_FATAL", FALSE), + NM_SETTING_IP_CONFIG_MAY_FAIL, !svGetValueBoolean (ifcfg, "IPV6_FAILURE_FATAL", FALSE), NM_SETTING_IP_CONFIG_ROUTE_METRIC, svGetValueInt64 (ifcfg, "IPV6_ROUTE_METRIC", 10, -1, G_MAXUINT32, -1), NM_SETTING_IP6_CONFIG_IP6_PRIVACY, ip6_privacy_val, @@ -1460,6 +1509,22 @@ make_ip6_setting (shvarFile *ifcfg, } } + /* IPv6 addressing mode configuration */ + tmp = svGetValue (ifcfg, "IPV6_ADDR_GEN_MODE", FALSE); + if (tmp) { + if (nm_utils_enum_from_str (nm_setting_ip6_config_addr_gen_mode_get_type (), tmp, + (int *) &addr_gen_mode, NULL)) + g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, addr_gen_mode, NULL); + else + PARSE_WARNING ("Invalid IPV6_ADDR_GEN_MODE"); + g_free (tmp); + } else { + g_object_set (s_ip6, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, + NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64, + NULL); + } + /* DNS servers * Pick up just IPv6 addresses (IPv4 addresses are taken by make_ip4_setting()) */ @@ -1500,9 +1565,17 @@ make_ip6_setting (shvarFile *ifcfg, g_free (route6_path); } + /* DNS options */ + value = svGetValueFull (ifcfg, "RES_OPTIONS", FALSE); + parse_dns_options (s_ip6, value); + parse_dns_options (s_ip6, dns_options); + g_free (value); + g_free (dns_options); + return NM_SETTING (s_ip6); error: + g_free (dns_options); g_free (route6_path); g_object_unref (s_ip6); return NULL; @@ -1579,11 +1652,11 @@ read_dcb_flags (shvarFile *ifcfg, DcbFlagsProperty *property) { NMSettingDcbFlags flags = NM_SETTING_DCB_FLAG_NONE; - if (svTrueValue (ifcfg, property->enable_key, FALSE)) + if (svGetValueBoolean (ifcfg, property->enable_key, FALSE)) flags |= NM_SETTING_DCB_FLAG_ENABLE; - if (svTrueValue (ifcfg, property->advertise_key, FALSE)) + if (svGetValueBoolean (ifcfg, property->advertise_key, FALSE)) flags |= NM_SETTING_DCB_FLAG_ADVERTISE; - if (svTrueValue (ifcfg, property->willing_key, FALSE)) + if (svGetValueBoolean (ifcfg, property->willing_key, FALSE)) flags |= NM_SETTING_DCB_FLAG_WILLING; return flags; @@ -1813,7 +1886,7 @@ make_dcb_setting (shvarFile *ifcfg, g_return_val_if_fail (out_setting != NULL, FALSE); - dcb_on = !!svTrueValue (ifcfg, "DCB", FALSE); + dcb_on = !!svGetValueBoolean (ifcfg, "DCB", FALSE); if (!dcb_on) return TRUE; @@ -2611,7 +2684,7 @@ eap_peap_reader (const char *eap_method, } } - if (svTrueValue (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", FALSE)) + if (svGetValueBoolean (ifcfg, "IEEE_8021X_PEAP_FORCE_NEW_LABEL", FALSE)) g_object_set (s_8021x, NM_SETTING_802_1X_PHASE1_PEAPLABEL, "1", NULL); anon_ident = svGetValue (ifcfg, "IEEE_8021X_ANON_IDENTITY", FALSE); @@ -3052,9 +3125,9 @@ make_wpa_setting (shvarFile *ifcfg, allow_wpa = svGetValue (ifcfg, "WPA_ALLOW_WPA", FALSE); allow_rsn = svGetValue (ifcfg, "WPA_ALLOW_WPA2", FALSE); - if (allow_wpa && svTrueValue (ifcfg, "WPA_ALLOW_WPA", TRUE)) + if (allow_wpa && svGetValueBoolean (ifcfg, "WPA_ALLOW_WPA", TRUE)) nm_setting_wireless_security_add_proto (wsec, "wpa"); - if (allow_rsn && svTrueValue (ifcfg, "WPA_ALLOW_WPA2", TRUE)) + if (allow_rsn && svGetValueBoolean (ifcfg, "WPA_ALLOW_WPA2", TRUE)) nm_setting_wireless_security_add_proto (wsec, "rsn"); /* If neither WPA_ALLOW_WPA or WPA_ALLOW_WPA2 were present, default @@ -3250,6 +3323,7 @@ make_wireless_setting (shvarFile *ifcfg, NMSettingWireless *s_wireless; char *value = NULL; gint64 chan = 0; + NMSettingMacRandomization mac_randomization = NM_SETTING_MAC_RANDOMIZATION_NEVER; s_wireless = NM_SETTING_WIRELESS (nm_setting_wireless_new ()); @@ -3424,7 +3498,34 @@ make_wireless_setting (shvarFile *ifcfg, g_object_set (s_wireless, NM_SETTING_WIRELESS_HIDDEN, - svTrueValue (ifcfg, "SSID_HIDDEN", FALSE), + svGetValueBoolean (ifcfg, "SSID_HIDDEN", FALSE), + NULL); + + g_object_set (s_wireless, + NM_SETTING_WIRELESS_POWERSAVE, + svGetValueBoolean (ifcfg, "POWERSAVE", FALSE) ? 1 : 0, + NULL); + + value = svGetValueFull (ifcfg, "MAC_ADDRESS_RANDOMIZATION", FALSE); + if (value) { + if (strcmp (value, "default") == 0) + mac_randomization = NM_SETTING_MAC_RANDOMIZATION_DEFAULT; + else if (strcmp (value, "never") == 0) + mac_randomization = NM_SETTING_MAC_RANDOMIZATION_NEVER; + else if (strcmp (value, "always") == 0) + mac_randomization = NM_SETTING_MAC_RANDOMIZATION_ALWAYS; + else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid MAC_ADDRESS_RANDOMIZATION value '%s'", value); + goto error; + } + g_free (value); + } else + mac_randomization = NM_SETTING_MAC_RANDOMIZATION_NEVER; + + g_object_set (s_wireless, + NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION, + mac_randomization, NULL); return NM_SETTING (s_wireless); @@ -3907,12 +4008,12 @@ make_infiniband_setting (shvarFile *ifcfg, g_free (value); } - if (svTrueValue (ifcfg, "CONNECTED_MODE", FALSE)) + if (svGetValueBoolean (ifcfg, "CONNECTED_MODE", FALSE)) g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "connected", NULL); else g_object_set (s_infiniband, NM_SETTING_INFINIBAND_TRANSPORT_MODE, "datagram", NULL); - if (svTrueValue (ifcfg, "PKEY", FALSE)) { + if (svGetValueBoolean (ifcfg, "PKEY", FALSE)) { int p_key; char *parent; @@ -4230,6 +4331,12 @@ handle_bridge_option (NMSetting *setting, g_object_set (setting, NM_SETTING_BRIDGE_AGEING_TIME, u, NULL); else PARSE_WARNING ("invalid ageing_time value '%s'", value); + } else if (!strcmp (key, "multicast_snooping")) { + if (get_uint (value, &u)) + g_object_set (setting, NM_SETTING_BRIDGE_MULTICAST_SNOOPING, + (gboolean) u, NULL); + else + PARSE_WARNING ("invalid multicast_snooping value '%s'", value); } else PARSE_WARNING ("unhandled bridge option '%s'", key); } @@ -4443,7 +4550,7 @@ is_bond_device (const char *name, shvarFile *parsed) g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (parsed != NULL, FALSE); - if (svTrueValue (parsed, "BONDING_MASTER", FALSE)) + if (svGetValueBoolean (parsed, "BONDING_MASTER", FALSE)) return TRUE; /* XXX: Check for "bond[\d]+"? */ @@ -4457,7 +4564,7 @@ is_vlan_device (const char *name, shvarFile *parsed) g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (parsed != NULL, FALSE); - if (svTrueValue (parsed, "VLAN", FALSE)) + if (svGetValueBoolean (parsed, "VLAN", FALSE)) return TRUE; return FALSE; @@ -4517,6 +4624,7 @@ make_vlan_setting (shvarFile *ifcfg, char *end = NULL; gint vlan_id = -1; guint32 vlan_flags = 0; + gint gvrp; value = svGetValue (ifcfg, "VLAN_ID", FALSE); if (value) { @@ -4591,17 +4699,25 @@ make_vlan_setting (shvarFile *ifcfg, g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, parent, NULL); g_clear_pointer (&parent, g_free); - if (svTrueValue (ifcfg, "REORDER_HDR", FALSE)) + if (svGetValueBoolean (ifcfg, "REORDER_HDR", FALSE)) vlan_flags |= NM_VLAN_FLAG_REORDER_HEADERS; + gvrp = svGetValueBoolean (ifcfg, "GVRP", -1); + if (gvrp > 0) + vlan_flags |= NM_VLAN_FLAG_GVRP; + value = svGetValue (ifcfg, "VLAN_FLAGS", FALSE); if (value) { - if (g_strstr_len (value, -1, "GVRP")) + /* Prefer GVRP variable; only take VLAN_FLAG=GVRP when GVRP is not specified */ + if (g_strstr_len (value, -1, "GVRP") && gvrp == -1) vlan_flags |= NM_VLAN_FLAG_GVRP; if (g_strstr_len (value, -1, "LOOSE_BINDING")) vlan_flags |= NM_VLAN_FLAG_LOOSE_BINDING; } + if (svGetValueBoolean (ifcfg, "MVRP", FALSE)) + vlan_flags |= NM_VLAN_FLAG_MVRP; + g_object_set (s_vlan, NM_SETTING_VLAN_FLAGS, vlan_flags, NULL); g_free (value); @@ -4807,7 +4923,7 @@ connection_from_file_full (const char *filename, if (!parsed) return NULL; - if (!svTrueValue (parsed, "NM_CONTROLLED", TRUE)) { + if (!svGetValueBoolean (parsed, "NM_CONTROLLED", TRUE)) { g_assert (out_unhandled != NULL); connection = create_unhandled_connection (filename, parsed, "unmanaged", out_unhandled); @@ -4886,7 +5002,7 @@ connection_from_file_full (const char *filename, } } - if (svTrueValue (parsed, "BONDING_MASTER", FALSE) && + if (svGetValueBoolean (parsed, "BONDING_MASTER", FALSE) && strcasecmp (type, TYPE_BOND)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "BONDING_MASTER=yes key only allowed in TYPE=bond connections"); diff --git a/src/settings/plugins/ifcfg-rh/reader.h b/src/settings/plugins/ifcfg-rh/reader.h index 2096ffc4..88f9a720 100644 --- a/src/settings/plugins/ifcfg-rh/reader.h +++ b/src/settings/plugins/ifcfg-rh/reader.h @@ -21,9 +21,9 @@ #ifndef __READER_H__ #define __READER_H__ -#include #include +#include "nm-default.h" #include "shvar.h" NMConnection *connection_from_file (const char *filename, diff --git a/src/settings/plugins/ifcfg-rh/shvar.c b/src/settings/plugins/ifcfg-rh/shvar.c index 5fd7755f..43068c67 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.c +++ b/src/settings/plugins/ifcfg-rh/shvar.c @@ -36,9 +36,8 @@ #include "shvar.h" -#include "gsystem-local-alloc.h" #include "nm-core-internal.h" -#include "nm-logging.h" +#include "nm-default.h" #define PARSE_WARNING(msg...) nm_log_warn (LOGD_SETTINGS, " " msg) @@ -299,35 +298,55 @@ svGetValueFull (shvarFile *s, const char *key, gboolean verbatim) return value; } -/* return TRUE if resolves to any truth value (e.g. "yes", "true", "y", "t", "1") - * return FALSE if resolves to any non-truth value (e.g. "no", "false", "n", "f", "0") - * return otherwise +/** + * svParseBoolean: + * @value: the input string + * @fallback: the fallback value + * + * Parses a string and returns the boolean value it contains or, + * in case no valid value is found, the fallback value. Valid values + * are: "yes", "true", "t", "y", "1" and "no", "false", "f", "n", "0". + * + * Returns: the parsed boolean value or @fallback. */ gint -svTrueValue (shvarFile *s, const char *key, gint def) +svParseBoolean (const char *value, gint fallback) { - char *tmp; - gint returnValue = def; + if (!value) + return fallback; - tmp = svGetValue (s, key, FALSE); - if (!tmp) - return returnValue; - - if ( !g_ascii_strcasecmp ("yes", tmp) - || !g_ascii_strcasecmp ("true", tmp) - || !g_ascii_strcasecmp ("t", tmp) - || !g_ascii_strcasecmp ("y", tmp) - || !g_ascii_strcasecmp ("1", tmp)) - returnValue = TRUE; - else if ( !g_ascii_strcasecmp ("no", tmp) - || !g_ascii_strcasecmp ("false", tmp) - || !g_ascii_strcasecmp ("f", tmp) - || !g_ascii_strcasecmp ("n", tmp) - || !g_ascii_strcasecmp ("0", tmp)) - returnValue = FALSE; + if ( !g_ascii_strcasecmp ("yes", value) + || !g_ascii_strcasecmp ("true", value) + || !g_ascii_strcasecmp ("t", value) + || !g_ascii_strcasecmp ("y", value) + || !g_ascii_strcasecmp ("1", value)) + return TRUE; + else if ( !g_ascii_strcasecmp ("no", value) + || !g_ascii_strcasecmp ("false", value) + || !g_ascii_strcasecmp ("f", value) + || !g_ascii_strcasecmp ("n", value) + || !g_ascii_strcasecmp ("0", value)) + return FALSE; + + return fallback; +} - g_free (tmp); - return returnValue; +/* svGetValueBoolean: + * @s: fhe file + * @key: the name of the key to read + * @fallback: the fallback value in any error case + * + * Reads a value @key and converts it to a boolean using svParseBoolean(). + * + * Returns: the parsed boolean value or @fallback. + */ +gint +svGetValueBoolean (shvarFile *s, const char *key, gint fallback) +{ + gs_free char *tmp = NULL; + + tmp = svGetValue (s, key, FALSE); + return svParseBoolean (tmp, fallback); } /* svGetValueInt64: @@ -426,6 +445,15 @@ svSetValueFull (shvarFile *s, const char *key, const char *value, gboolean verba g_free (keyValue); } +void +svSetValueInt64 (shvarFile *s, const char *key, gint64 value) +{ + gs_free char *v = NULL; + + v = g_strdup_printf ("%"G_GINT64_FORMAT, value); + svSetValueFull (s, key, v, TRUE); +} + /* Write the current contents iff modified. Returns FALSE on error * and TRUE on success. Do not write if no values have been modified. * The mode argument is only used if creating the file, not if diff --git a/src/settings/plugins/ifcfg-rh/shvar.h b/src/settings/plugins/ifcfg-rh/shvar.h index de7a3585..227a44db 100644 --- a/src/settings/plugins/ifcfg-rh/shvar.h +++ b/src/settings/plugins/ifcfg-rh/shvar.h @@ -31,7 +31,7 @@ #ifndef _SHVAR_H #define _SHVAR_H -#include +#include "nm-default.h" G_BEGIN_DECLS @@ -58,11 +58,13 @@ shvarFile *svOpenFile (const char *name, GError **error); char *svGetValue (shvarFile *s, const char *key, gboolean verbatim); char *svGetValueFull (shvarFile *s, const char *key, gboolean verbatim); +gint svParseBoolean (const char *value, gint def); + /* return TRUE if resolves to any truth value (e.g. "yes", "y", "true") * return FALSE if resolves to any non-truth value (e.g. "no", "n", "false") * return otherwise */ -gint svTrueValue (shvarFile *s, const char *key, gint def); +gint svGetValueBoolean (shvarFile *s, const char *key, gint def); gint64 svGetValueInt64 (shvarFile *s, const char *key, guint base, gint64 min, gint64 max, gint64 fallback); @@ -73,6 +75,7 @@ gint64 svGetValueInt64 (shvarFile *s, const char *key, guint base, gint64 min, g */ void svSetValue (shvarFile *s, const char *key, const char *value, gboolean verbatim); void svSetValueFull (shvarFile *s, const char *key, const char *value, gboolean verbatim); +void svSetValueInt64 (shvarFile *s, const char *key, gint64 value); /* Write the current contents iff modified. Returns FALSE on error diff --git a/src/settings/plugins/ifcfg-rh/tests/Makefile.am b/src/settings/plugins/ifcfg-rh/tests/Makefile.am index 73f3b5d8..25d27197 100644 --- a/src/settings/plugins/ifcfg-rh/tests/Makefile.am +++ b/src/settings/plugins/ifcfg-rh/tests/Makefile.am @@ -7,8 +7,8 @@ SUBDIRS=network-scripts AM_CPPFLAGS = \ $(GLIB_CFLAGS) \ $(CODE_COVERAGE_CFLAGS) \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -I$(top_srcdir)/src/ \ @@ -16,7 +16,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src/settings \ -I$(srcdir)/../ \ -DG_LOG_DOMAIN=\""NetworkManager-ifcfg-rh"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ -DTEST_IFCFG_DIR=\"$(abs_srcdir)\" \ -DTEST_SCRATCH_DIR=\"$(abs_builddir)/\" \ @@ -25,7 +25,6 @@ AM_CPPFLAGS = \ AM_LDFLAGS = \ $(GLIB_LIBS) \ - $(DBUS_LIBS) \ $(CODE_COVERAGE_LDFLAGS) noinst_PROGRAMS = test-ifcfg-rh test-ifcfg-rh-utils diff --git a/src/settings/plugins/ifcfg-rh/tests/Makefile.in b/src/settings/plugins/ifcfg-rh/tests/Makefile.in index da25c8b9..00636de9 100644 --- a/src/settings/plugins/ifcfg-rh/tests/Makefile.in +++ b/src/settings/plugins/ifcfg-rh/tests/Makefile.in @@ -459,7 +459,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -471,8 +470,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -482,6 +479,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -536,16 +534,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -582,6 +577,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -610,7 +607,6 @@ 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@ @@ -625,6 +621,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -685,6 +683,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -692,6 +691,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -711,8 +711,8 @@ with_valgrind = @with_valgrind@ @ENABLE_TESTS_TRUE@AM_CPPFLAGS = \ @ENABLE_TESTS_TRUE@ $(GLIB_CFLAGS) \ @ENABLE_TESTS_TRUE@ $(CODE_COVERAGE_CFLAGS) \ -@ENABLE_TESTS_TRUE@ -I$(top_srcdir)/include \ -@ENABLE_TESTS_TRUE@ -I$(top_builddir)/include \ +@ENABLE_TESTS_TRUE@ -I$(top_srcdir)/shared \ +@ENABLE_TESTS_TRUE@ -I$(top_builddir)/shared \ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/libnm-core \ @ENABLE_TESTS_TRUE@ -I$(top_builddir)/libnm-core \ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/src/ \ @@ -720,7 +720,7 @@ with_valgrind = @with_valgrind@ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/src/settings \ @ENABLE_TESTS_TRUE@ -I$(srcdir)/../ \ @ENABLE_TESTS_TRUE@ -DG_LOG_DOMAIN=\""NetworkManager-ifcfg-rh"\" \ -@ENABLE_TESTS_TRUE@ -DNETWORKMANAGER_COMPILATION \ +@ENABLE_TESTS_TRUE@ -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ @ENABLE_TESTS_TRUE@ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ @ENABLE_TESTS_TRUE@ -DTEST_IFCFG_DIR=\"$(abs_srcdir)\" \ @ENABLE_TESTS_TRUE@ -DTEST_SCRATCH_DIR=\"$(abs_builddir)/\" \ @@ -729,7 +729,6 @@ with_valgrind = @with_valgrind@ @ENABLE_TESTS_TRUE@AM_LDFLAGS = \ @ENABLE_TESTS_TRUE@ $(GLIB_LIBS) \ -@ENABLE_TESTS_TRUE@ $(DBUS_LIBS) \ @ENABLE_TESTS_TRUE@ $(CODE_COVERAGE_LDFLAGS) @ENABLE_TESTS_TRUE@test_ifcfg_rh_SOURCES = \ diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am index c3fde548..a1b414fd 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.am @@ -67,6 +67,10 @@ EXTRA_DIST = \ ifcfg-test-wifi-band-a \ ifcfg-test-wifi-band-a-channel-mismatch \ ifcfg-test-wifi-band-bg-channel-mismatch \ + ifcfg-test-wifi-mac-random-always \ + ifcfg-test-wifi-mac-random-never \ + ifcfg-test-wifi-mac-random-default \ + ifcfg-test-wifi-mac-random-missing \ test_ca_cert.pem \ test1_key_and_cert.pem \ ifcfg-test-ibft \ @@ -102,6 +106,8 @@ EXTRA_DIST = \ ifcfg-test-vlan-only-device \ ifcfg-test-vlan-physdev \ ifcfg-test-vlan-reorder-hdr-1 \ + ifcfg-test-vlan-flags-1 \ + ifcfg-test-vlan-flags-2 \ ifcfg-test-wifi-wep-no-keys \ ifcfg-test-permissions \ ifcfg-test-wifi-wep-agent-keys \ @@ -127,6 +133,7 @@ EXTRA_DIST = \ ifcfg-test-team-port \ ifcfg-test-team-port-empty-config \ ifcfg-test-vlan-trailing-spaces \ + ifcfg-test-dns-options \ ifcfg-test-wired-wake-on-lan \ ifcfg-test-wired-ipv6-only-1 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in index 4add27b7..cae7067e 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/Makefile.in @@ -146,7 +146,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -158,8 +157,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -169,6 +166,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -223,16 +221,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -269,6 +264,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -297,7 +294,6 @@ 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@ @@ -312,6 +308,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -372,6 +370,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -379,6 +378,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -463,6 +463,10 @@ EXTRA_DIST = \ ifcfg-test-wifi-band-a \ ifcfg-test-wifi-band-a-channel-mismatch \ ifcfg-test-wifi-band-bg-channel-mismatch \ + ifcfg-test-wifi-mac-random-always \ + ifcfg-test-wifi-mac-random-never \ + ifcfg-test-wifi-mac-random-default \ + ifcfg-test-wifi-mac-random-missing \ test_ca_cert.pem \ test1_key_and_cert.pem \ ifcfg-test-ibft \ @@ -498,6 +502,8 @@ EXTRA_DIST = \ ifcfg-test-vlan-only-device \ ifcfg-test-vlan-physdev \ ifcfg-test-vlan-reorder-hdr-1 \ + ifcfg-test-vlan-flags-1 \ + ifcfg-test-vlan-flags-2 \ ifcfg-test-wifi-wep-no-keys \ ifcfg-test-permissions \ ifcfg-test-wifi-wep-agent-keys \ @@ -523,6 +529,7 @@ EXTRA_DIST = \ ifcfg-test-team-port \ ifcfg-test-team-port-empty-config \ ifcfg-test-vlan-trailing-spaces \ + ifcfg-test-dns-options \ ifcfg-test-wired-wake-on-lan \ ifcfg-test-wired-ipv6-only-1 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bridge-main b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bridge-main index ee7a8dc6..1d31b5ba 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bridge-main +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-bridge-main @@ -4,5 +4,5 @@ TYPE=Bridge BOOTPROTO=dhcp STP=on DELAY=2 -BRIDGING_OPTS="priority=32744 hello_time=7 max_age=39 ageing_time=235352" +BRIDGING_OPTS="priority=32744 hello_time=7 max_age=39 ageing_time=235352 multicast_snooping=0" MACADDR=00:16:41:11:22:33 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options new file mode 100644 index 00000000..62e301e3 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-dns-options @@ -0,0 +1,15 @@ +TYPE=Ethernet +DEVICE=eth2 +HWADDR=00:11:22:33:44:ee +BOOTPROTO=dhcp +ONBOOT=yes +USERCTL=yes +NM_CONTROLLED=yes +PEERDNS=yes +DNS1=10.2.0.4 +DOMAIN="lorem.com ipsum.org dolor.edu" +RES_OPTIONS="ndots:3 single-request-reopen inet6" +IPV6INIT=yes +IPV6_AUTOCONF=no +IPV6ADDR="1001:abba::1234/56" +IPV6ADDR_SECONDARIES="2001:abba::2234/64 3001:abba::3234/96" diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-flags-1 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-flags-1 new file mode 100644 index 00000000..5ff87891 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-flags-1 @@ -0,0 +1,14 @@ +VLAN=yes +TYPE=Vlan +DEVICE=super-vlan +VLAN_ID=44 +PHYSDEV=eth9 +REORDER_HDR=yes +GVRP=no +VLAN_FLAGS="GVRP LOOSE_BINDING" +VLAN_INGRESS_PRIORITY_MAP=0:1,2:5 +VLAN_EGRESS_PRIORITY_MAP=12:3,14:7,3:1 +ONBOOT=yes +BOOTPROTO=static +IPADDR=192.168.43.149 +NETMASK=255.255.255.0 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-flags-2 b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-flags-2 new file mode 100644 index 00000000..3b536a66 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-vlan-flags-2 @@ -0,0 +1,11 @@ +VLAN=yes +TYPE=Vlan +DEVICE=super-vlan +VLAN_ID=44 +PHYSDEV=eth9 +REORDER_HDR=no +VLAN_FLAGS="GVRP LOOSE_BINDING" +ONBOOT=yes +BOOTPROTO=static +IPADDR=192.168.43.149 +NETMASK=255.255.255.0 diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-always b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-always new file mode 100644 index 00000000..9dcb5bf8 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-always @@ -0,0 +1,7 @@ +TYPE=Wireless +DEVICE=eth2 +BOOTPROTO=dhcp +ESSID=blahblah +ONBOOT=yes +MAC_ADDRESS_RANDOMIZATION=always + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-default b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-default new file mode 100644 index 00000000..3709c493 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-default @@ -0,0 +1,6 @@ +TYPE=Wireless +DEVICE=eth2 +BOOTPROTO=dhcp +ESSID=blahblah +ONBOOT=yes +MAC_ADDRESS_RANDOMIZATION=default diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-missing b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-missing new file mode 100644 index 00000000..f896eb0f --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-missing @@ -0,0 +1,6 @@ +TYPE=Wireless +DEVICE=eth2 +BOOTPROTO=dhcp +ESSID=blahblah +ONBOOT=yes + diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-never b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-never new file mode 100644 index 00000000..aa12d749 --- /dev/null +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wifi-mac-random-never @@ -0,0 +1,6 @@ +TYPE=Wireless +DEVICE=eth2 +BOOTPROTO=dhcp +ESSID=blahblah +ONBOOT=yes +MAC_ADDRESS_RANDOMIZATION=never diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static index c8315f45..6d49c01c 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static @@ -18,3 +18,4 @@ IPV6ADDR=dead:beaf::1 IPV6ADDR_SECONDARIES="dead:beaf::2/56" DNS3=1:2:3:4::a DNS4=1:2:3:4::b +RES_OPTIONS= diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static-bootproto b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static-bootproto index ee821503..a01f6558 100644 --- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static-bootproto +++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-test-wired-static-bootproto @@ -13,3 +13,4 @@ DNS2=4.2.2.2 IPADDR=192.168.1.5 NETMASK=255.255.255.0 GATEWAY=192.168.1.1 +RES_OPTIONS= diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c index cd2d0417..b7a887d0 100644 --- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c +++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c @@ -54,10 +54,16 @@ #include "reader.h" #include "writer.h" #include "utils.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-test-utils.h" +typedef struct { + const char *name; + const NMSettingMacRandomization value; + const char *write_expected; +} WifiMacRandomData; + #if 0 static void connection_diff (NMConnection *a, NMConnection *b) @@ -484,6 +490,9 @@ test_read_wired_static (const char *file, g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL); g_assert (nm_setting_ip_config_get_may_fail (s_ip4)); + g_assert (nm_setting_ip_config_has_dns_options (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns_options (s_ip4), ==, 0); + /* DNS Addresses */ g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip4), ==, 2); g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip4, 0), ==, "4.2.2.1"); @@ -506,6 +515,9 @@ test_read_wired_static (const char *file, g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_MANUAL); g_assert (nm_setting_ip_config_get_may_fail (s_ip6)); + g_assert (nm_setting_ip_config_has_dns_options (s_ip6)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns_options (s_ip6), ==, 0); + /* DNS Addresses */ g_assert_cmpint (nm_setting_ip_config_get_num_dns (s_ip6), ==, 2); g_assert_cmpstr (nm_setting_ip_config_get_dns (s_ip6, 0), ==, "1:2:3:4::a"); @@ -525,6 +537,7 @@ test_read_wired_static (const char *file, g_assert_cmpstr (nm_ip_address_get_address (ip6_addr), ==, "dead:beaf::2"); } else { g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip6), ==, NM_SETTING_IP6_CONFIG_METHOD_IGNORE); + g_assert (!nm_setting_ip_config_has_dns_options (s_ip6)); } g_object_unref (connection); @@ -563,6 +576,9 @@ test_read_wired_static_no_prefix (gconstpointer user_data) g_assert (s_ip4); g_assert_cmpstr (nm_setting_ip_config_get_method (s_ip4), ==, NM_SETTING_IP4_CONFIG_METHOD_MANUAL); + g_assert (!nm_setting_ip_config_has_dns_options (s_ip4)); + g_assert_cmpint (nm_setting_ip_config_get_num_dns_options (s_ip4), ==, 0); + g_assert_cmpint (nm_setting_ip_config_get_num_addresses (s_ip4), ==, 1); ip4_addr = nm_setting_ip_config_get_address (s_ip4, 0); g_assert (ip4_addr); @@ -2535,6 +2551,165 @@ test_read_wired_aliases_bad_2 (void) test_read_wired_aliases_bad (TEST_IFCFG_ALIASES_BAD_2, "System aliasem2"); } +#define TEST_IFCFG_DNS_OPTIONS TEST_IFCFG_DIR "/network-scripts/ifcfg-test-dns-options" + +static void +test_read_dns_options (void) +{ + NMConnection *connection; + NMSettingIPConfig *s_ip4, *s_ip6; + char *unmanaged = NULL; + const char *option; + GError *error = NULL; + const char *options[] = { "ndots:3", "single-request-reopen", "inet6" }; + guint32 i, options_len = sizeof (options) / sizeof (options[0]); + + connection = connection_from_file_test (TEST_IFCFG_DNS_OPTIONS, + NULL, + TYPE_ETHERNET, + &unmanaged, + &error); + g_assert (connection); + g_assert (nm_connection_verify (connection, &error)); + g_assert_cmpstr (unmanaged, ==, NULL); + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + g_assert (s_ip4); + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + g_assert (s_ip6); + + i = nm_setting_ip_config_get_num_dns_options (s_ip4); + g_assert_cmpint (i, ==, options_len); + + i = nm_setting_ip_config_get_num_dns_options (s_ip6); + g_assert_cmpint (i, ==, options_len); + + for (i = 0; i < options_len; i++) { + option = nm_setting_ip_config_get_dns_option (s_ip4, i); + g_assert_cmpstr (options[i], ==, option); + + option = nm_setting_ip_config_get_dns_option (s_ip6, i); + g_assert_cmpstr (options[i], ==, option); + } + + g_object_unref (connection); +} + +static void +test_write_dns_options (void) +{ + NMConnection *connection; + NMConnection *reread; + NMSettingConnection *s_con; + NMSettingWired *s_wired; + NMSettingIPConfig *s_ip4; + NMSettingIPConfig *s_ip6; + static const char *mac = "31:33:33:37:be:cd"; + guint32 mtu = 1492; + char *uuid; + NMIPAddress *addr; + NMIPAddress *addr6; + gboolean success; + GError *error = NULL; + char *testfile = NULL; + + connection = nm_simple_connection_new (); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_setting_connection_new (); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + uuid = nm_utils_uuid_generate (); + g_object_set (s_con, + NM_SETTING_CONNECTION_ID, "Test DNS options", + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, + NULL); + g_free (uuid); + + /* Wired setting */ + s_wired = (NMSettingWired *) nm_setting_wired_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wired)); + + g_object_set (s_wired, + NM_SETTING_WIRED_MAC_ADDRESS, mac, + NM_SETTING_WIRED_MTU, mtu, + NULL); + + /* IP4 setting */ + s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new (); + nm_connection_add_setting (connection, NM_SETTING (s_ip4)); + + g_object_set (s_ip4, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, + NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE, + NM_SETTING_IP_CONFIG_GATEWAY, "1.1.1.1", + NM_SETTING_IP_CONFIG_ROUTE_METRIC, (gint64) 204, + NULL); + + addr = nm_ip_address_new (AF_INET, "1.1.1.3", 24, &error); + nm_setting_ip_config_add_address (s_ip4, addr); + nm_ip_address_unref (addr); + + /* IP6 setting */ + s_ip6 = (NMSettingIPConfig *) nm_setting_ip6_config_new (); + nm_connection_add_setting (connection, NM_SETTING (s_ip6)); + + g_object_set (s_ip6, + NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_MANUAL, + NM_SETTING_IP_CONFIG_MAY_FAIL, TRUE, + NM_SETTING_IP_CONFIG_ROUTE_METRIC, (gint64) 206, + NULL); + + /* Add addresses */ + addr6 = nm_ip_address_new (AF_INET6, "1003:1234:abcd::1", 11, &error); + nm_setting_ip_config_add_address (s_ip6, addr6); + nm_ip_address_unref (addr6); + + nm_setting_ip_config_add_dns_option (s_ip4, "debug"); + nm_setting_ip_config_add_dns_option (s_ip6, "timeout:3"); + + g_assert (nm_connection_verify (connection, &error)); + + /* Save the ifcfg */ + success = writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile, + &error); + g_assert (success); + g_assert (testfile); + + /* reread will be normalized, so we must normalize connection too. */ + nm_connection_normalize (connection, NULL, NULL, NULL); + + /* re-read the connection for comparison */ + reread = connection_from_file_test (testfile, + NULL, + TYPE_ETHERNET, + NULL, + &error); + unlink (testfile); + + /* RES_OPTIONS is copied to both IPv4 and IPv6 settings */ + nm_setting_ip_config_clear_dns_options (s_ip4, TRUE); + nm_setting_ip_config_add_dns_option (s_ip4, "debug"); + nm_setting_ip_config_add_dns_option (s_ip4, "timeout:3"); + + nm_setting_ip_config_clear_dns_options (s_ip6, TRUE); + nm_setting_ip_config_add_dns_option (s_ip6, "debug"); + nm_setting_ip_config_add_dns_option (s_ip6, "timeout:3"); + + g_assert (reread); + g_assert (nm_connection_verify (reread, &error)); + g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT)); + + g_free (testfile); + g_object_unref (connection); + g_object_unref (reread); +} + #define TEST_IFCFG_WIFI_OPEN TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-open" static void @@ -5296,6 +5471,117 @@ test_write_wifi_hidden (void) g_object_unref (reread); } +static void +test_read_wifi_mac_random (gconstpointer user_data) +{ + const WifiMacRandomData *test_data = user_data; + NMConnection *connection; + NMSettingWireless *s_wifi; + gboolean success; + GError *error = NULL; + char *path; + + path = g_strdup_printf (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-wifi-mac-random-%s", test_data->name); + connection = connection_from_file_test (path, NULL, TYPE_WIRELESS, NULL, &error); + g_free (path); + g_assert_no_error (error); + g_assert (connection); + + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + s_wifi = nm_connection_get_setting_wireless (connection); + g_assert (s_wifi); + g_assert_cmpint (nm_setting_wireless_get_mac_address_randomization (s_wifi), ==, test_data->value); + + g_object_unref (connection); +} + +static void +test_write_wifi_mac_random (gconstpointer user_data) +{ + const WifiMacRandomData *test_data = user_data; + NMConnection *connection, *reread; + NMSettingConnection *s_con; + NMSettingWireless *s_wifi; + char *uuid, *testfile = NULL, *val; + gboolean success; + GError *error = NULL; + shvarFile *f; + GBytes *ssid; + const unsigned char ssid_data[] = { 0x54, 0x65, 0x73, 0x74, 0x20, 0x53, 0x53, 0x49, 0x44 }; + + connection = nm_simple_connection_new (); + + /* Connection setting */ + s_con = (NMSettingConnection *) nm_setting_connection_new (); + nm_connection_add_setting (connection, NM_SETTING (s_con)); + + uuid = nm_utils_uuid_generate (); + val = g_strdup_printf ("Test Write WiFi MAC %s", test_data->name); + g_object_set (s_con, + NM_SETTING_CONNECTION_ID, val, + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME, + NULL); + g_free (uuid); + g_free (val); + + /* Wifi setting */ + s_wifi = (NMSettingWireless *) nm_setting_wireless_new (); + nm_connection_add_setting (connection, NM_SETTING (s_wifi)); + + ssid = g_bytes_new (ssid_data, sizeof (ssid_data)); + g_object_set (s_wifi, + NM_SETTING_WIRELESS_SSID, ssid, + NM_SETTING_WIRELESS_MODE, "infrastructure", + NM_SETTING_WIRELESS_MAC_ADDRESS_RANDOMIZATION, test_data->value, + NULL); + g_bytes_unref (ssid); + + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + + /* Save the ifcfg */ + success = writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &testfile, + &error); + g_assert_no_error (error); + g_assert (success); + + f = svOpenFile (testfile, &error); + g_assert_no_error (error); + g_assert (f); + + /* re-read the file to check that what key was written. */ + val = svGetValue (f, "MAC_ADDRESS_RANDOMIZATION", FALSE); + g_assert_cmpstr (val, ==, test_data->write_expected); + g_free (val); + svCloseFile (f); + + /* reread will be normalized, so we must normalize connection too. */ + nm_connection_normalize (connection, NULL, NULL, NULL); + + /* re-read the connection for comparison */ + reread = connection_from_file_test (testfile, NULL, TYPE_WIRELESS, NULL, &error); + unlink (testfile); + g_assert_no_error (error); + g_assert (reread); + + success = nm_connection_verify (reread, &error); + g_assert_no_error (error); + g_assert (success); + + g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT)); + + g_free (testfile); + g_object_unref (connection); + g_object_unref (reread); +} + static void test_write_wired_wake_on_lan (void) { @@ -6356,7 +6642,6 @@ test_write_wired_static_ip6_only (void) gboolean success; GError *error = NULL; char *testfile = NULL; - char *route6file = NULL; connection = nm_simple_connection_new (); @@ -6441,7 +6726,6 @@ test_write_wired_static_ip6_only (void) "wired-static-ip6-only-write", "written and re-read connection weren't the same."); g_free (testfile); - g_free (route6file); g_object_unref (connection); g_object_unref (reread); } @@ -6592,8 +6876,8 @@ test_read_write_static_routes_legacy (void) NMSettingWired *s_wired; NMSettingIPConfig *s_ip4; char *testfile = NULL; - char *routefile2 = NULL; - char *route6file2 = NULL; + char *routefile = NULL; + char *route6file = NULL; gboolean success; GError *error = NULL; const char *tmp; @@ -6689,17 +6973,14 @@ test_read_write_static_routes_legacy (void) NULL, &error); unlink (testfile); - routefile2 = utils_get_route_path (testfile); - unlink (routefile2); - route6file2 = utils_get_route6_path (testfile); - unlink (route6file2); + routefile = utils_get_route_path (testfile); + unlink (routefile); + route6file = utils_get_route6_path (testfile); + unlink (route6file); ASSERT (reread != NULL, "read-write-static-routes-legacy-reread", "failed to read %s: %s", testfile, error->message); - ASSERT (routefile2 != NULL, - "read-write-static-routes-legacy-reread", "expected routefile for '%s'", testfile); - ASSERT (nm_connection_verify (reread, &error), "read-write-static-routes-legacy-reread-verify", "failed to verify %s: %s", testfile, error->message); @@ -6707,8 +6988,8 @@ test_read_write_static_routes_legacy (void) "read-write-static-routes-legacy-write", "written and re-read connection weren't the same."); g_free (testfile); - g_free (routefile2); - g_free (route6file2); + g_free (routefile); + g_free (route6file); g_object_unref (connection); g_object_unref (reread); } @@ -9859,7 +10140,6 @@ test_write_wired_qeth_dhcp (void) gboolean success; GError *error = NULL; char *testfile = NULL; - char *route6file = NULL; connection = nm_simple_connection_new (); @@ -9947,7 +10227,6 @@ test_write_wired_qeth_dhcp (void) "wired-qeth-dhcp-write", "written and re-read connection weren't the same."); g_free (testfile); - g_free (route6file); g_object_unref (connection); g_object_unref (reread); } @@ -9966,7 +10245,6 @@ test_write_wired_ctc_dhcp (void) gboolean success; GError *error = NULL; char *testfile = NULL; - char *route6file = NULL; shvarFile *ifcfg; char *tmp; @@ -10066,7 +10344,6 @@ test_write_wired_ctc_dhcp (void) g_assert (success); g_free (testfile); - g_free (route6file); g_object_unref (connection); g_object_unref (reread); } @@ -10084,7 +10361,6 @@ test_write_permissions (void) gboolean success; GError *error = NULL; char *testfile = NULL; - char *route6file = NULL; connection = nm_simple_connection_new (); @@ -10164,7 +10440,6 @@ test_write_permissions (void) "permissions-write", "written and re-read connection weren't the same."); g_free (testfile); - g_free (route6file); g_object_unref (connection); g_object_unref (reread); } @@ -10185,7 +10460,6 @@ test_write_wifi_wep_agent_keys (void) gboolean success; GError *error = NULL; char *testfile = NULL; - char *route6file = NULL; connection = nm_simple_connection_new (); g_assert (connection != NULL); @@ -10290,7 +10564,6 @@ test_write_wifi_wep_agent_keys (void) g_assert (success); g_free (testfile); - g_free (route6file); g_object_unref (connection); g_object_unref (reread); } @@ -10544,6 +10817,7 @@ test_read_bridge_main (void) g_assert_cmpuint (nm_setting_bridge_get_hello_time (s_bridge), ==, 7); g_assert_cmpuint (nm_setting_bridge_get_max_age (s_bridge), ==, 39); g_assert_cmpuint (nm_setting_bridge_get_ageing_time (s_bridge), ==, 235352); + g_assert (!nm_setting_bridge_get_multicast_snooping (s_bridge)); /* MAC address */ mac = nm_setting_bridge_get_mac_address (s_bridge); @@ -10702,7 +10976,6 @@ test_write_bridge_component (void) gboolean success; GError *error = NULL; char *testfile = NULL; - char *route6file = NULL; connection = nm_simple_connection_new (); g_assert (connection); @@ -10773,7 +11046,6 @@ test_write_bridge_component (void) g_assert (nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT)); g_free (testfile); - g_free (route6file); g_object_unref (connection); g_object_unref (reread); } @@ -10849,17 +11121,17 @@ test_read_vlan_interface (void) g_assert_cmpint (nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_EGRESS_MAP), ==, 3); g_assert (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, 0, &from, &to)); + g_assert_cmpint (from, ==, 3); + g_assert_cmpint (to, ==, 1); + + g_assert (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, 1, &from, &to)); g_assert_cmpint (from, ==, 12); g_assert_cmpint (to, ==, 3); - g_assert (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, 1, &from, &to)); + g_assert (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, 2, &from, &to)); g_assert_cmpint (from, ==, 14); g_assert_cmpint (to, ==, 7); - g_assert (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, 2, &from, &to)); - g_assert_cmpint (from, ==, 3); - g_assert_cmpint (to, ==, 1); - g_object_unref (connection); } @@ -10975,6 +11247,62 @@ test_read_vlan_reorder_hdr_1 (void) g_object_unref (connection); } +static void +test_read_vlan_flags_1 (void) +{ + NMConnection *connection; + GError *error = NULL; + NMSettingVlan *s_vlan; + + connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-vlan-flags-1", + NULL, + TYPE_ETHERNET, + NULL, + &error); + g_assert_no_error (error); + g_assert (connection != NULL); + + g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, "super-vlan"); + + s_vlan = nm_connection_get_setting_vlan (connection); + g_assert (s_vlan); + + g_assert_cmpstr (nm_setting_vlan_get_parent (s_vlan), ==, "eth9"); + g_assert_cmpint (nm_setting_vlan_get_id (s_vlan), ==, 44); + /* reorder_hdr and loose_binding */ + g_assert_cmpint (nm_setting_vlan_get_flags (s_vlan), ==, 5); + + g_object_unref (connection); +} + +static void +test_read_vlan_flags_2 (void) +{ + NMConnection *connection; + GError *error = NULL; + NMSettingVlan *s_vlan; + + connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-vlan-flags-2", + NULL, + TYPE_ETHERNET, + NULL, + &error); + g_assert_no_error (error); + g_assert (connection != NULL); + + g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, "super-vlan"); + + s_vlan = nm_connection_get_setting_vlan (connection); + g_assert (s_vlan); + + g_assert_cmpstr (nm_setting_vlan_get_parent (s_vlan), ==, "eth9"); + g_assert_cmpint (nm_setting_vlan_get_id (s_vlan), ==, 44); + /* gvrp and loose_binding */ + g_assert_cmpint (nm_setting_vlan_get_flags (s_vlan), ==, 6); + + g_object_unref (connection); +} + static void test_write_vlan (void) { @@ -11002,6 +11330,54 @@ test_write_vlan (void) g_object_unref (connection); } +static void +test_write_vlan_flags (void) +{ + NMConnection *connection, *reread; + char *written = NULL; + GError *error = NULL; + gboolean success = FALSE; + + connection = connection_from_file_test (TEST_IFCFG_DIR"/network-scripts/ifcfg-test-vlan-flags-2", + NULL, + TYPE_VLAN, + NULL, + &error); + g_assert (connection != NULL); + + success = writer_new_connection (connection, + TEST_SCRATCH_DIR "/network-scripts/", + &written, + &error); + g_assert (success); + + /* reread will be normalized, so we must normalize connection too. */ + nm_connection_normalize (connection, NULL, NULL, NULL); + + /* re-read the connection for comparison */ + reread = connection_from_file_test (written, + NULL, + TYPE_ETHERNET, + NULL, + &error); + + unlink (written); + g_free (written); + + g_assert_no_error (error); + g_assert (reread != NULL); + + success = nm_connection_verify (reread, &error); + g_assert_no_error (error); + g_assert (success); + + success = nm_connection_compare (connection, reread, NM_SETTING_COMPARE_FLAG_EXACT); + g_assert (success); + + g_object_unref (connection); + g_object_unref (reread); +} + static void test_write_vlan_only_vlanid (void) { @@ -11434,7 +11810,6 @@ test_write_bond_slave (void) gboolean success; GError *error = NULL; char *testfile = NULL; - char *route6file = NULL; connection = nm_simple_connection_new (); @@ -11499,7 +11874,6 @@ test_write_bond_slave (void) "bond-slave-write", "written and re-read connection weren't the same."); g_free (testfile); - g_free (route6file); g_object_unref (connection); g_object_unref (reread); } @@ -11724,7 +12098,6 @@ test_write_bond_slave_ib (void) gboolean success; GError *error = NULL; char *testfile = NULL; - char *route6file = NULL; connection = nm_simple_connection_new (); @@ -11790,7 +12163,6 @@ test_write_bond_slave_ib (void) "bond-slave-write-ib", "written and re-read connection weren't the same."); g_free (testfile); - g_free (route6file); g_object_unref (connection); g_object_unref (reread); } @@ -12741,6 +13113,7 @@ int main (int argc, char **argv) g_test_add_data_func (TPATH "static-ip6-only-gw/::", "::", test_write_wired_static_ip6_only_gw); g_test_add_data_func (TPATH "static-ip6-only-gw/2001:db8:8:4::2", "2001:db8:8:4::2", test_write_wired_static_ip6_only_gw); g_test_add_data_func (TPATH "static-ip6-only-gw/::ffff:255.255.255.255", "::ffff:255.255.255.255", test_write_wired_static_ip6_only_gw); + g_test_add_func (TPATH "read-dns-options", test_read_dns_options); test_read_wired_static (TEST_IFCFG_WIRED_STATIC, "System test-wired-static", TRUE); test_read_wired_static (TEST_IFCFG_WIRED_STATIC_BOOTPROTO, "System test-wired-static-bootproto", FALSE); @@ -12805,6 +13178,35 @@ int main (int argc, char **argv) g_test_add_func (TPATH "wifi/read-band-a-channel-mismatch", test_read_wifi_band_a_channel_mismatch); g_test_add_func (TPATH "wifi/read-band-bg-channel-mismatch", test_read_wifi_band_bg_channel_mismatch); g_test_add_func (TPATH "wifi/read-hidden", test_read_wifi_hidden); + + { + static const WifiMacRandomData test_wifi_mac_random[] = { + { "always", NM_SETTING_MAC_RANDOMIZATION_ALWAYS, "always" }, + { "never", NM_SETTING_MAC_RANDOMIZATION_NEVER, "never" }, + { "default", NM_SETTING_MAC_RANDOMIZATION_DEFAULT, "default" }, + { "missing", NM_SETTING_MAC_RANDOMIZATION_NEVER, "never" }, + }; + int i; + + for (i = 0; i < G_N_ELEMENTS (test_wifi_mac_random); i++) { + char *tpath; + + tpath = g_strdup_printf (TPATH "wifi/read-mac-random-%s", test_wifi_mac_random[i].name); + g_test_add_data_func_full (tpath, + g_memdup (&test_wifi_mac_random[i], sizeof (test_wifi_mac_random[i])), + test_read_wifi_mac_random, + g_free); + g_free (tpath); + + tpath = g_strdup_printf (TPATH "wifi/write-mac-random-%s", test_wifi_mac_random[i].name); + g_test_add_data_func_full (tpath, + g_memdup (&test_wifi_mac_random[i], sizeof (test_wifi_mac_random[i])), + test_write_wifi_mac_random, + g_free); + g_free (tpath); + } + } + test_read_wired_qeth_static (); test_read_wired_ctc_static (); test_read_wifi_wep_no_keys (); @@ -12812,6 +13214,8 @@ int main (int argc, char **argv) test_read_wifi_wep_agent_keys (); test_read_infiniband (); test_read_vlan_interface (); + g_test_add_func (TPATH "vlan/read-flags-1", test_read_vlan_flags_1); + g_test_add_func (TPATH "vlan/read-flags-2", test_read_vlan_flags_2); test_read_vlan_only_vlan_id (); test_read_vlan_only_device (); g_test_add_func (TPATH "vlan/physdev", test_read_vlan_physdev); @@ -12894,9 +13298,11 @@ int main (int argc, char **argv) test_write_wifi_wep_agent_keys (); test_write_infiniband (); test_write_vlan (); + g_test_add_func (TPATH "vlan/write-flags", test_write_vlan_flags); test_write_vlan_only_vlanid (); g_test_add_func (TPATH "vlan/write-vlan-reorder-hdr", test_write_vlan_reorder_hdr); test_write_ethernet_missing_ipv6 (); + g_test_add_func (TPATH "write-dns-options", test_write_dns_options); /* iSCSI / ibft */ g_test_add_func (TPATH "ibft/ignored", test_read_ibft_ignored); diff --git a/src/settings/plugins/ifcfg-rh/utils.c b/src/settings/plugins/ifcfg-rh/utils.c index a793288d..599e3a49 100644 --- a/src/settings/plugins/ifcfg-rh/utils.c +++ b/src/settings/plugins/ifcfg-rh/utils.c @@ -20,14 +20,13 @@ #include "config.h" -#include #include #include +#include "nm-default.h" #include "nm-core-internal.h" #include "nm-macros-internal.h" #include "NetworkManagerUtils.h" -#include "gsystem-local-alloc.h" #include "utils.h" #include "shvar.h" diff --git a/src/settings/plugins/ifcfg-rh/utils.h b/src/settings/plugins/ifcfg-rh/utils.h index 547bfcb2..329f4547 100644 --- a/src/settings/plugins/ifcfg-rh/utils.h +++ b/src/settings/plugins/ifcfg-rh/utils.h @@ -21,11 +21,10 @@ #ifndef _UTILS_H_ #define _UTILS_H_ -#include #include +#include "nm-default.h" #include "shvar.h" #include "common.h" -#include "nm-logging.h" #define NM_IFCFG_CONNECTION_LOG_PATH(path) str_if_set (path,"in-memory") #define NM_IFCFG_CONNECTION_LOG_FMT "%s (%s,\"%s\")" diff --git a/src/settings/plugins/ifcfg-rh/writer.c b/src/settings/plugins/ifcfg-rh/writer.c index 3640a104..5770d668 100644 --- a/src/settings/plugins/ifcfg-rh/writer.c +++ b/src/settings/plugins/ifcfg-rh/writer.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2009 - 2014 Red Hat, Inc. + * Copyright 2009 - 2015 Red Hat, Inc. */ #include "config.h" @@ -45,8 +45,7 @@ #include "nm-core-internal.h" #include "nm-macros-internal.h" -#include "nm-logging.h" -#include "gsystem-local-alloc.h" +#include "nm-default.h" #include "common.h" #include "shvar.h" #include "reader.h" @@ -968,7 +967,7 @@ write_wireless_setting (NMConnection *connection, tmp = g_strdup_printf ("KEY_PASSPHRASE%d", i + 1); set_secret (ifcfg, tmp, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE, FALSE); g_free (tmp); - + tmp = g_strdup_printf ("KEY%d", i + 1); set_secret (ifcfg, tmp, NULL, "WEP_KEY_FLAGS", NM_SETTING_SECRET_FLAG_NONE, FALSE); g_free (tmp); @@ -988,6 +987,21 @@ write_wireless_setting (NMConnection *connection, } svSetValue (ifcfg, "SSID_HIDDEN", nm_setting_wireless_get_hidden (s_wireless) ? "yes" : NULL, TRUE); + svSetValue (ifcfg, "POWERSAVE", nm_setting_wireless_get_powersave (s_wireless) ? "yes" : NULL, TRUE); + + svSetValue (ifcfg, "MAC_ADDRESS_RANDOMIZATION", NULL, TRUE); + switch (nm_setting_wireless_get_mac_address_randomization (s_wireless)) { + case NM_SETTING_MAC_RANDOMIZATION_DEFAULT: + svSetValue (ifcfg, "MAC_ADDRESS_RANDOMIZATION", "default", TRUE); + break; + case NM_SETTING_MAC_RANDOMIZATION_ALWAYS: + svSetValue (ifcfg, "MAC_ADDRESS_RANDOMIZATION", "always", TRUE); + break; + default: + case NM_SETTING_MAC_RANDOMIZATION_NEVER: + svSetValue (ifcfg, "MAC_ADDRESS_RANDOMIZATION", "never", TRUE); + break; + } svSetValue (ifcfg, "TYPE", TYPE_WIRELESS, FALSE); @@ -1268,15 +1282,14 @@ write_vlan_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wired, else svSetValue (ifcfg, "REORDER_HDR", "no", FALSE); + svSetValue (ifcfg, "GVRP", vlan_flags & NM_VLAN_FLAG_GVRP ? "yes" : "no", FALSE); + svSetValue (ifcfg, "VLAN_FLAGS", NULL, FALSE); - if (vlan_flags & NM_VLAN_FLAG_GVRP) { - if (vlan_flags & NM_VLAN_FLAG_LOOSE_BINDING) - svSetValue (ifcfg, "VLAN_FLAGS", "GVRP,LOOSE_BINDING", FALSE); - else - svSetValue (ifcfg, "VLAN_FLAGS", "GVRP", FALSE); - } else if (vlan_flags & NM_VLAN_FLAG_LOOSE_BINDING) + if (vlan_flags & NM_VLAN_FLAG_LOOSE_BINDING) svSetValue (ifcfg, "VLAN_FLAGS", "LOOSE_BINDING", FALSE); + svSetValue (ifcfg, "MVRP", vlan_flags & NM_VLAN_FLAG_MVRP ? "yes" : "no", FALSE); + tmp = vlan_priority_maplist_to_stringlist (s_vlan, NM_VLAN_INGRESS_MAP); svSetValue (ifcfg, "VLAN_INGRESS_PRIORITY_MAP", tmp, FALSE); g_free (tmp); @@ -1380,7 +1393,7 @@ write_team_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wired, } static guint32 -get_setting_default (NMSetting *setting, const char *prop) +get_setting_default_uint (NMSetting *setting, const char *prop) { GParamSpec *pspec; GValue val = G_VALUE_INIT; @@ -1396,12 +1409,30 @@ get_setting_default (NMSetting *setting, const char *prop) return ret; } +static gboolean +get_setting_default_boolean (NMSetting *setting, const char *prop) +{ + GParamSpec *pspec; + GValue val = G_VALUE_INIT; + gboolean ret = 0; + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), prop); + g_assert (pspec); + g_value_init (&val, pspec->value_type); + g_param_value_set_default (pspec, &val); + g_assert (G_VALUE_HOLDS_BOOLEAN (&val)); + ret = g_value_get_boolean (&val); + g_value_unset (&val); + return ret; +} + static gboolean write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) { NMSettingBridge *s_bridge; const char *iface; guint32 i; + gboolean b; GString *opts; const char *mac; char *s; @@ -1435,7 +1466,7 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, GError **error svSetValue (ifcfg, "STP", "yes", FALSE); i = nm_setting_bridge_get_forward_delay (s_bridge); - if (i != get_setting_default (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_FORWARD_DELAY)) { + if (i != get_setting_default_uint (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_FORWARD_DELAY)) { s = g_strdup_printf ("%u", i); svSetValue (ifcfg, "DELAY", s, FALSE); g_free (s); @@ -1444,14 +1475,14 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, GError **error g_string_append_printf (opts, "priority=%u", nm_setting_bridge_get_priority (s_bridge)); i = nm_setting_bridge_get_hello_time (s_bridge); - if (i != get_setting_default (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_HELLO_TIME)) { + if (i != get_setting_default_uint (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_HELLO_TIME)) { if (opts->len) g_string_append_c (opts, ' '); g_string_append_printf (opts, "hello_time=%u", i); } i = nm_setting_bridge_get_max_age (s_bridge); - if (i != get_setting_default (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_MAX_AGE)) { + if (i != get_setting_default_uint (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_MAX_AGE)) { if (opts->len) g_string_append_c (opts, ' '); g_string_append_printf (opts, "max_age=%u", i); @@ -1459,12 +1490,19 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, GError **error } i = nm_setting_bridge_get_ageing_time (s_bridge); - if (i != get_setting_default (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_AGEING_TIME)) { + if (i != get_setting_default_uint (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_AGEING_TIME)) { if (opts->len) g_string_append_c (opts, ' '); g_string_append_printf (opts, "ageing_time=%u", i); } + b = nm_setting_bridge_get_multicast_snooping (s_bridge); + if (b != get_setting_default_boolean (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_MULTICAST_SNOOPING)) { + if (opts->len) + g_string_append_c (opts, ' '); + g_string_append_printf (opts, "multicast_snooping=%u", (guint32) b); + } + if (opts->len) svSetValue (ifcfg, "BRIDGING_OPTS", opts->str, FALSE); g_string_free (opts, TRUE); @@ -1491,11 +1529,11 @@ write_bridge_port_setting (NMConnection *connection, shvarFile *ifcfg, GError ** opts = g_string_sized_new (32); i = nm_setting_bridge_port_get_priority (s_port); - if (i != get_setting_default (NM_SETTING (s_port), NM_SETTING_BRIDGE_PORT_PRIORITY)) + if (i != get_setting_default_uint (NM_SETTING (s_port), NM_SETTING_BRIDGE_PORT_PRIORITY)) g_string_append_printf (opts, "priority=%u", i); i = nm_setting_bridge_port_get_path_cost (s_port); - if (i != get_setting_default (NM_SETTING (s_port), NM_SETTING_BRIDGE_PORT_PATH_COST)) { + if (i != get_setting_default_uint (NM_SETTING (s_port), NM_SETTING_BRIDGE_PORT_PATH_COST)) { if (opts->len) g_string_append_c (opts, ' '); g_string_append_printf (opts, "path_cost=%u", i); @@ -1753,6 +1791,18 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg) FALSE); } + switch (nm_setting_connection_get_lldp (s_con)) { + case NM_SETTING_CONNECTION_LLDP_ENABLE_RX: + tmp = "rx"; + break; + case NM_SETTING_CONNECTION_LLDP_DISABLE: + tmp = "no"; + break; + default: + tmp = NULL; + } + svSetValue (ifcfg, "LLDP", tmp, FALSE); + /* Permissions */ svSetValue (ifcfg, "USERS", NULL, FALSE); n = nm_setting_connection_get_num_permissions (s_con); @@ -1897,6 +1947,7 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) gint32 j; guint32 i, n, num; gint64 route_metric; + int dhcp_timeout; GString *searches; gboolean success = FALSE; gboolean fake_ip4 = FALSE; @@ -2090,6 +2141,10 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) if (value) svSetValue (ifcfg, "DHCP_HOSTNAME", value, FALSE); + value = nm_setting_ip4_config_get_dhcp_fqdn (NM_SETTING_IP4_CONFIG (s_ip4)); + if (value) + svSetValue (ifcfg, "DHCP_FQDN", value, FALSE); + /* Missing DHCP_SEND_HOSTNAME means TRUE, and we prefer not write it explicitly * in that case, because it is NM-specific variable */ @@ -2100,6 +2155,11 @@ write_ip4_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) value = nm_setting_ip4_config_get_dhcp_client_id (NM_SETTING_IP4_CONFIG (s_ip4)); if (value) svSetValue (ifcfg, "DHCP_CLIENT_ID", value, FALSE); + + dhcp_timeout = nm_setting_ip4_config_get_dhcp_timeout (NM_SETTING_IP4_CONFIG (s_ip4)); + tmp = dhcp_timeout ? g_strdup_printf ("%d", dhcp_timeout) : NULL; + svSetValue (ifcfg, "IPV4_DHCP_TIMEOUT", tmp, FALSE); + g_free (tmp); } svSetValue (ifcfg, "IPV4_FAILURE_FATAL", @@ -2353,6 +2413,7 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) gint64 route_metric; GString *ip_str1, *ip_str2, *ip_ptr; char *route6_path; + NMSettingIP6ConfigAddrGenMode addr_gen_mode; s_ip6 = nm_connection_get_setting_ip6_config (connection); if (!s_ip6) { @@ -2365,6 +2426,7 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) svSetValue (ifcfg, "IPV6_PEERROUTES", "yes", FALSE); svSetValue (ifcfg, "IPV6_FAILURE_FATAL", "no", FALSE); svSetValue (ifcfg, "IPV6_ROUTE_METRIC", NULL, FALSE); + svSetValue (ifcfg, "IPV6_ADDR_GEN_MODE", "stable-privacy", FALSE); return TRUE; } @@ -2502,6 +2564,15 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error) break; } + /* IPv6 Address generation mode */ + addr_gen_mode = nm_setting_ip6_config_get_addr_gen_mode (NM_SETTING_IP6_CONFIG (s_ip6)); + if (addr_gen_mode != NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64) { + tmp = nm_utils_enum_to_str (nm_setting_ip6_config_addr_gen_mode_get_type (), + addr_gen_mode); + svSetValue (ifcfg, "IPV6_ADDR_GEN_MODE", tmp, FALSE); + g_free (tmp); + } + /* Static routes go to route6- file */ route6_path = utils_get_route6_path (ifcfg->fileName); if (!route6_path) { @@ -2520,6 +2591,63 @@ error: return FALSE; } +static void +add_dns_option (GPtrArray *array, const char *option) +{ + if (_nm_utils_dns_option_find_idx (array, option) < 0) + g_ptr_array_add (array, (gpointer) option); +} + +static gboolean +write_res_options (NMConnection *connection, shvarFile *ifcfg, GError **error) +{ + NMSettingIPConfig *s_ip6; + NMSettingIPConfig *s_ip4; + const char *method; + int i, num_options; + GPtrArray *array; + GString *value; + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + s_ip6 = nm_connection_get_setting_ip6_config (connection); + array = g_ptr_array_new (); + + if (s_ip4) { + method = nm_setting_ip_config_get_method (s_ip4); + if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED)) { + num_options = nm_setting_ip_config_get_num_dns_options (s_ip4); + for (i = 0; i < num_options; i++) + add_dns_option (array, nm_setting_ip_config_get_dns_option (s_ip4, i)); + } + } + + if (s_ip6) { + method = nm_setting_ip_config_get_method (s_ip6); + if (g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE)) { + num_options = nm_setting_ip_config_get_num_dns_options (s_ip6); + for (i = 0; i < num_options; i++) + add_dns_option (array, nm_setting_ip_config_get_dns_option (s_ip6, i)); + } + } + + if (array->len > 0 + || (s_ip4 && nm_setting_ip_config_has_dns_options (s_ip4)) + || (s_ip6 && nm_setting_ip_config_has_dns_options (s_ip6))) { + value = g_string_new (NULL); + for (i = 0; i < array->len; i++) { + if (i > 0) + g_string_append_c (value, ' '); + g_string_append (value, array->pdata[i]); + } + svSetValueFull (ifcfg, "RES_OPTIONS", value->str, FALSE); + g_string_free (value, TRUE); + } else + svSetValue (ifcfg, "RES_OPTIONS", NULL, FALSE); + + g_ptr_array_unref (array); + return TRUE; +} + static char * escape_id (const char *id) { @@ -2660,6 +2788,7 @@ write_connection (NMConnection *connection, if (!utils_ignore_ip_config (connection)) { svSetValue (ifcfg, "DHCP_HOSTNAME", NULL, FALSE); + svSetValue (ifcfg, "DHCP_FQDN", NULL, FALSE); if (!write_ip4_setting (connection, ifcfg, error)) goto out; @@ -2667,6 +2796,9 @@ write_connection (NMConnection *connection, if (!write_ip6_setting (connection, ifcfg, error)) goto out; + + if (!write_res_options (connection, ifcfg, error)) + goto out; } write_connection_setting (s_con, ifcfg); diff --git a/src/settings/plugins/ifcfg-rh/writer.h b/src/settings/plugins/ifcfg-rh/writer.h index 894313dd..69389361 100644 --- a/src/settings/plugins/ifcfg-rh/writer.h +++ b/src/settings/plugins/ifcfg-rh/writer.h @@ -22,9 +22,11 @@ #define _WRITER_H_ #include -#include + #include +#include "nm-default.h" + gboolean writer_can_write_connection (NMConnection *connection, GError **error); diff --git a/src/settings/plugins/ifcfg-suse/Makefile.am b/src/settings/plugins/ifcfg-suse/Makefile.am deleted file mode 100644 index 55494536..00000000 --- a/src/settings/plugins/ifcfg-suse/Makefile.am +++ /dev/null @@ -1,20 +0,0 @@ -AM_CPPFLAGS = \ - $(GLIB_CFLAGS) \ - -I${top_srcdir}/src \ - -I${top_srcdir}/src/settings \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ - -I$(top_srcdir)/libnm-core \ - -I$(top_builddir)/libnm-core \ - -DG_LOG_DOMAIN=\""NetworkManager-ifcfg-suse"\" \ - -DNETWORKMANAGER_COMPILATION \ - -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - -DSYSCONFDIR=\"$(sysconfdir)\" - -pkglib_LTLIBRARIES = libnm-settings-plugin-ifcfg-suse.la - -libnm_settings_plugin_ifcfg_suse_la_SOURCES = \ - plugin.c \ - plugin.h - -libnm_settings_plugin_ifcfg_suse_la_LDFLAGS = -module -avoid-version diff --git a/src/settings/plugins/ifcfg-suse/Makefile.in b/src/settings/plugins/ifcfg-suse/Makefile.in deleted file mode 100644 index fa51b0aa..00000000 --- a/src/settings/plugins/ifcfg-suse/Makefile.in +++ /dev/null @@ -1,819 +0,0 @@ -# Makefile.in generated by automake 1.15 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2014 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 = { \ - if test -z '$(MAKELEVEL)'; then \ - false; \ - elif test -n '$(MAKE_HOST)'; then \ - true; \ - elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ - true; \ - else \ - false; \ - fi; \ -} -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/settings/plugins/ifcfg-suse -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) -DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__installdirs = "$(DESTDIR)$(pkglibdir)" -LTLIBRARIES = $(pkglib_LTLIBRARIES) -libnm_settings_plugin_ifcfg_suse_la_LIBADD = -am_libnm_settings_plugin_ifcfg_suse_la_OBJECTS = plugin.lo -libnm_settings_plugin_ifcfg_suse_la_OBJECTS = \ - $(am_libnm_settings_plugin_ifcfg_suse_la_OBJECTS) -AM_V_lt = $(am__v_lt_@AM_V@) -am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) -am__v_lt_0 = --silent -am__v_lt_1 = -libnm_settings_plugin_ifcfg_suse_la_LINK = $(LIBTOOL) $(AM_V_lt) \ - --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ - $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libnm_settings_plugin_ifcfg_suse_la_LDFLAGS) $(LDFLAGS) -o \ - $@ -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(CFLAGS) -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = -CCLD = $(CC) -LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = -SOURCES = $(libnm_settings_plugin_ifcfg_suse_la_SOURCES) -DIST_SOURCES = $(libnm_settings_plugin_ifcfg_suse_la_SOURCES) -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -am__DIST_COMMON = $(srcdir)/Makefile.in \ - $(top_srcdir)/build-aux/depcomp -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -ALL_LINGUAS = @ALL_LINGUAS@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AM_TESTS_FD_REDIRECT = @AM_TESTS_FD_REDIRECT@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BLUEZ5_CFLAGS = @BLUEZ5_CFLAGS@ -BLUEZ5_LIBS = @BLUEZ5_LIBS@ -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@ -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_CHECK_PATH = @GTKDOC_CHECK_PATH@ -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@ -LOG_DRIVER = @LOG_DRIVER@ -LTLIBICONV = @LTLIBICONV@ -LTLIBINTL = @LTLIBINTL@ -LTLIBOBJS = @LTLIBOBJS@ -LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ -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_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ -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@ -PERL = @PERL@ -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_DIR = @UDEV_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 = \ - $(GLIB_CFLAGS) \ - -I${top_srcdir}/src \ - -I${top_srcdir}/src/settings \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ - -I$(top_srcdir)/libnm-core \ - -I$(top_builddir)/libnm-core \ - -DG_LOG_DOMAIN=\""NetworkManager-ifcfg-suse"\" \ - -DNETWORKMANAGER_COMPILATION \ - -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - -DSYSCONFDIR=\"$(sysconfdir)\" - -pkglib_LTLIBRARIES = libnm-settings-plugin-ifcfg-suse.la -libnm_settings_plugin_ifcfg_suse_la_SOURCES = \ - plugin.c \ - plugin.h - -libnm_settings_plugin_ifcfg_suse_la_LDFLAGS = -module -avoid-version -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/settings/plugins/ifcfg-suse/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu src/settings/plugins/ifcfg-suse/Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES) - @$(NORMAL_INSTALL) - @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \ - } - -uninstall-pkglibLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \ - done - -clean-pkglibLTLIBRARIES: - -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES) - @list='$(pkglib_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } - -libnm-settings-plugin-ifcfg-suse.la: $(libnm_settings_plugin_ifcfg_suse_la_OBJECTS) $(libnm_settings_plugin_ifcfg_suse_la_DEPENDENCIES) $(EXTRA_libnm_settings_plugin_ifcfg_suse_la_DEPENDENCIES) - $(AM_V_CCLD)$(libnm_settings_plugin_ifcfg_suse_la_LINK) -rpath $(pkglibdir) $(libnm_settings_plugin_ifcfg_suse_la_OBJECTS) $(libnm_settings_plugin_ifcfg_suse_la_LIBADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Plo@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< - -.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 -o $@ `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-am - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-am - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: check-am -all-am: Makefile $(LTLIBRARIES) -installdirs: - for dir in "$(DESTDIR)$(pkglibdir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - 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-pkglibLTLIBRARIES \ - mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: install-pkglibLTLIBRARIES - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-pkglibLTLIBRARIES - -.MAKE: install-am install-strip - -.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ - clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \ - ctags-am distclean distclean-compile distclean-generic \ - distclean-libtool distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-pdf install-pdf-am \ - install-pkglibLTLIBRARIES install-ps install-ps-am \ - install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ - pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ - uninstall-pkglibLTLIBRARIES - -.PRECIOUS: Makefile - - -# 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/settings/plugins/ifcfg-suse/plugin.c b/src/settings/plugins/ifcfg-suse/plugin.c deleted file mode 100644 index a1667f64..00000000 --- a/src/settings/plugins/ifcfg-suse/plugin.c +++ /dev/null @@ -1,312 +0,0 @@ -/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */ - -/* NetworkManager system settings service - * - * Søren Sandmann - * - * 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. - * - * (C) Copyright 2007 - 2011 Red Hat, Inc. - * (C) Copyright 2007 - 2008 Novell, Inc. - */ - -#include "config.h" - -#include - -#include -#include -#include - -#include "plugin.h" -#include "nm-system-config-interface.h" - -#define IFCFG_PLUGIN_NAME "ifcfg-suse" -#define IFCFG_PLUGIN_INFO "(C) 2008 Novell, Inc. To report bugs please use the NetworkManager mailing list." -#define IFCFG_DIR SYSCONFDIR "/sysconfig/network" -#define CONF_DHCP IFCFG_DIR "/dhcp" -#define HOSTNAME_FILE "/etc/HOSTNAME" - -static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class); - -G_DEFINE_TYPE_EXTENDED (SCPluginIfcfg, sc_plugin_ifcfg, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, - system_config_interface_init)) - -#define SC_PLUGIN_IFCFG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfgPrivate)) - - -#define IFCFG_FILE_PATH_TAG "ifcfg-file-path" - -typedef struct { - GFileMonitor *hostname_monitor; - GFileMonitor *dhcp_monitor; - char *hostname; -} SCPluginIfcfgPrivate; - -typedef void (*FileChangedFn) (gpointer user_data); - -typedef struct { - FileChangedFn callback; - gpointer user_data; -} FileMonitorInfo; - -static void -file_changed (GFileMonitor *monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer user_data) -{ - FileMonitorInfo *info; - - switch (event_type) { - case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: - case G_FILE_MONITOR_EVENT_DELETED: - info = (FileMonitorInfo *) user_data; - info->callback (info->user_data); - break; - default: - break; - } -} - -static GFileMonitor * -monitor_file_changes (const char *filename, - FileChangedFn callback, - gpointer user_data) -{ - GFile *file; - GFileMonitor *monitor; - FileMonitorInfo *info; - - file = g_file_new_for_path (filename); - monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); - g_object_unref (file); - - if (monitor) { - info = g_new0 (FileMonitorInfo, 1); - info->callback = callback; - info->user_data = user_data; - g_object_weak_ref (G_OBJECT (monitor), (GWeakNotify) g_free, info); - g_signal_connect (monitor, "changed", G_CALLBACK (file_changed), info); - } - - return monitor; -} - -static gboolean -hostname_is_dynamic (void) -{ - GIOChannel *channel; - const char *pattern = "DHCLIENT_SET_HOSTNAME="; - char *str = NULL; - int pattern_len; - gboolean dynamic = FALSE; - - channel = g_io_channel_new_file (CONF_DHCP, "r", NULL); - if (!channel) - return dynamic; - - pattern_len = strlen (pattern); - - while (g_io_channel_read_line (channel, &str, NULL, NULL, NULL) != G_IO_STATUS_EOF) { - if (!strncmp (str, pattern, pattern_len)) { - if (!strncmp (str + pattern_len, "\"yes\"", 5)) - dynamic = TRUE; - break; - } - g_free (str); - } - - g_io_channel_shutdown (channel, FALSE, NULL); - g_io_channel_unref (channel); - - return dynamic; -} - -static char * -hostname_read (void) -{ - GIOChannel *channel; - char *hostname = NULL; - - channel = g_io_channel_new_file (HOSTNAME_FILE, "r", NULL); - if (channel) { - g_io_channel_read_line (channel, &hostname, NULL, NULL, NULL); - g_io_channel_shutdown (channel, FALSE, NULL); - g_io_channel_unref (channel); - - if (hostname) - hostname = g_strchomp (hostname); - } - - return hostname; -} - -static void -hostname_changed (gpointer data) -{ - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (data); - - g_free (priv->hostname); - if (hostname_is_dynamic ()) - priv->hostname = NULL; - else - priv->hostname = hostname_read (); - - g_object_notify (G_OBJECT (data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); -} - -static void -plugin_set_hostname (SCPluginIfcfg *plugin, const char *hostname) -{ - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin); - GIOChannel *channel; - - channel = g_io_channel_new_file (HOSTNAME_FILE, "w", NULL); - if (channel) { - g_io_channel_write_chars (channel, hostname, -1, NULL, NULL); - g_io_channel_write_chars (channel, "\n", -1, NULL, NULL); - g_io_channel_shutdown (channel, TRUE, NULL); - g_io_channel_unref (channel); - } - - g_free (priv->hostname); - priv->hostname = g_strdup (hostname); -} - -static void -init (NMSystemConfigInterface *config) -{ - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (config); - - priv->hostname_monitor = monitor_file_changes (HOSTNAME_FILE, hostname_changed, config); - priv->dhcp_monitor = monitor_file_changes (CONF_DHCP, hostname_changed, config); - - if (!hostname_is_dynamic ()) - priv->hostname = hostname_read (); -} - -static void -sc_plugin_ifcfg_init (SCPluginIfcfg *self) -{ -} - -static void -dispose (GObject *object) -{ - SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (object); - - if (priv->dhcp_monitor) - g_object_unref (priv->dhcp_monitor); - - if (priv->hostname_monitor) - g_object_unref (priv->hostname_monitor); - - g_free (priv->hostname); - - G_OBJECT_CLASS (sc_plugin_ifcfg_parent_class)->dispose (object); -} - -static void -get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) -{ - switch (prop_id) { - case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME: - g_value_set_string (value, IFCFG_PLUGIN_NAME); - break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO: - g_value_set_string (value, IFCFG_PLUGIN_INFO); - break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES: - g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME); - break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME: - g_value_set_string (value, SC_PLUGIN_IFCFG_GET_PRIVATE (object)->hostname); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - const char *hostname; - - switch (prop_id) { - case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME: - hostname = g_value_get_string (value); - if (hostname && strlen (hostname) < 1) - hostname = NULL; - plugin_set_hostname (SC_PLUGIN_IFCFG (object), hostname); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -sc_plugin_ifcfg_class_init (SCPluginIfcfgClass *req_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (req_class); - - g_type_class_add_private (req_class, sizeof (SCPluginIfcfgPrivate)); - - object_class->get_property = get_property; - object_class->set_property = set_property; - object_class->dispose = dispose; - - g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME, - NM_SYSTEM_CONFIG_INTERFACE_NAME); - - g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, - NM_SYSTEM_CONFIG_INTERFACE_INFO); - - g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES, - NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES); - - g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME, - NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); -} - -static void -system_config_interface_init (NMSystemConfigInterface *system_config_interface_class) -{ - /* interface implementation */ - system_config_interface_class->init = init; -} - -G_MODULE_EXPORT GObject * -nm_system_config_factory (void) -{ - static SCPluginIfcfg *singleton = NULL; - - if (!singleton) - singleton = SC_PLUGIN_IFCFG (g_object_new (SC_TYPE_PLUGIN_IFCFG, NULL)); - else - g_object_ref (singleton); - - return G_OBJECT (singleton); -} diff --git a/src/settings/plugins/ifcfg-suse/plugin.h b/src/settings/plugins/ifcfg-suse/plugin.h deleted file mode 100644 index 24dbff95..00000000 --- a/src/settings/plugins/ifcfg-suse/plugin.h +++ /dev/null @@ -1,50 +0,0 @@ -/* NetworkManager system settings service - * - * Søren Sandmann - * - * 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. - * - * (C) Copyright 2007 Red Hat, Inc. - */ - -#ifndef _PLUGIN_H_ -#define _PLUGIN_H_ - -#include - -#define PLUGIN_NAME "ifcfg-suse" - -#define SC_TYPE_PLUGIN_IFCFG (sc_plugin_ifcfg_get_type ()) -#define SC_PLUGIN_IFCFG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfg)) -#define SC_PLUGIN_IFCFG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfgClass)) -#define SC_IS_PLUGIN_IFCFG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_IFCFG)) -#define SC_IS_PLUGIN_IFCFG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_PLUGIN_IFCFG)) -#define SC_PLUGIN_IFCFG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_IFCFG, SCPluginIfcfgClass)) - -typedef struct _SCPluginIfcfg SCPluginIfcfg; -typedef struct _SCPluginIfcfgClass SCPluginIfcfgClass; - -struct _SCPluginIfcfg { - GObject parent; -}; - -struct _SCPluginIfcfgClass { - GObjectClass parent; -}; - -GType sc_plugin_ifcfg_get_type (void); - -#endif /* _PLUGIN_H_ */ - diff --git a/src/settings/plugins/ifnet/Makefile.am b/src/settings/plugins/ifnet/Makefile.am index 84e2e697..ffd8ab3c 100644 --- a/src/settings/plugins/ifnet/Makefile.am +++ b/src/settings/plugins/ifnet/Makefile.am @@ -6,12 +6,12 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/platform \ -I$(top_srcdir)/src/settings \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-ifnet"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ -DSYSCONFDIR=\"$(sysconfdir)\" diff --git a/src/settings/plugins/ifnet/Makefile.in b/src/settings/plugins/ifnet/Makefile.in index 589f1f22..c6e13316 100644 --- a/src/settings/plugins/ifnet/Makefile.in +++ b/src/settings/plugins/ifnet/Makefile.in @@ -278,7 +278,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -290,8 +289,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -301,6 +298,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -355,16 +353,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -401,6 +396,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -429,7 +426,6 @@ 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@ @@ -444,6 +440,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -504,6 +502,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -511,6 +510,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -531,12 +531,12 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/platform \ -I$(top_srcdir)/src/settings \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-ifnet"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ -DSYSCONFDIR=\"$(sysconfdir)\" diff --git a/src/settings/plugins/ifnet/connection_parser.c b/src/settings/plugins/ifnet/connection_parser.c index 888ee589..51ff9da6 100644 --- a/src/settings/plugins/ifnet/connection_parser.c +++ b/src/settings/plugins/ifnet/connection_parser.c @@ -25,10 +25,9 @@ #include #include #include -#include -#include "nm-system-config-interface.h" -#include "nm-logging.h" +#include "nm-settings-plugin.h" +#include "nm-default.h" #include "nm-core-internal.h" #include "NetworkManagerUtils.h" diff --git a/src/settings/plugins/ifnet/net_parser.c b/src/settings/plugins/ifnet/net_parser.c index 8f528d0f..ee66ff53 100644 --- a/src/settings/plugins/ifnet/net_parser.c +++ b/src/settings/plugins/ifnet/net_parser.c @@ -26,8 +26,8 @@ #include #include -#include -#include +#include +#include "nm-default.h" #include "plugin.h" #include "nm-platform.h" diff --git a/src/settings/plugins/ifnet/net_parser.h b/src/settings/plugins/ifnet/net_parser.h index d10979cc..968feaf5 100644 --- a/src/settings/plugins/ifnet/net_parser.h +++ b/src/settings/plugins/ifnet/net_parser.h @@ -22,7 +22,7 @@ #ifndef _NET_PARSER_H #define _NET_PARSER_H -#include +#include "nm-default.h" #define CONF_NET_FILE SYSCONFDIR "/conf.d/net" diff --git a/src/settings/plugins/ifnet/net_utils.c b/src/settings/plugins/ifnet/net_utils.c index adb23c43..1c72e0b2 100644 --- a/src/settings/plugins/ifnet/net_utils.c +++ b/src/settings/plugins/ifnet/net_utils.c @@ -26,11 +26,10 @@ #include #include #include -#include -#include -#include -#include -#include +#include "NetworkManagerUtils.h" +#include +#include "nm-config.h" +#include "nm-default.h" #include "net_utils.h" #include "wpa_parser.h" #include "net_parser.h" @@ -136,47 +135,6 @@ reload_parsers (void) return TRUE; } -gchar * -read_hostname (const char *path) -{ - gchar *contents = NULL, *result = NULL, *tmp; - gchar **all_lines = NULL; - guint line_num, i; - - if (!g_file_get_contents (path, &contents, NULL, NULL)) - return NULL; - all_lines = g_strsplit (contents, "\n", 0); - line_num = g_strv_length (all_lines); - for (i = 0; i < line_num; i++) { - g_strstrip (all_lines[i]); - if (all_lines[i][0] == '#' || all_lines[i][0] == '\0') - continue; - if (g_str_has_prefix (all_lines[i], "hostname")) { - tmp = strstr (all_lines[i], "="); - tmp++; - result = g_shell_unquote (tmp, NULL); - break; - } - - } - g_strfreev (all_lines); - g_free (contents); - return result; -} - -gboolean -write_hostname (const char *path, const gchar *hostname) -{ - gboolean result; - char *contents; - - contents = g_strdup_printf ("#Generated by NetworkManager\n" - "hostname=\"%s\"\n", hostname); - result = g_file_set_contents (path, contents, -1, NULL); - g_free (contents); - return result; -} - gboolean is_static_ip4 (const char *conn_name) { diff --git a/src/settings/plugins/ifnet/net_utils.h b/src/settings/plugins/ifnet/net_utils.h index d58e7ec6..45969369 100644 --- a/src/settings/plugins/ifnet/net_utils.h +++ b/src/settings/plugins/ifnet/net_utils.h @@ -21,11 +21,11 @@ #ifndef _IFNET_UTILS_H #define _IFNET_UTILS_H -#define IFNET_PLUGIN_NAME "SCPlugin-Ifnet" -#include +#define IFNET_PLUGIN_NAME "SettingsPlugin-Ifnet" #include #include #include +#include "nm-default.h" #include "net_parser.h" #define has_default_ip4_route(conn_name) has_default_route((conn_name), &is_ip4_address) #define has_default_ip6_route(conn_name) has_default_route((conn_name), &is_ip6_address) @@ -37,8 +37,6 @@ typedef struct _ip_block { struct _ip_block *next; } ip_block; -gchar *read_hostname (const char *path); -gboolean write_hostname (const char *path, const char *hostname); gboolean is_static_ip4 (const char *conn_name); gboolean is_static_ip6 (const char *conn_name); gboolean is_ip4_address (const char *in_address); diff --git a/src/settings/plugins/ifnet/nm-ifnet-connection.c b/src/settings/plugins/ifnet/nm-ifnet-connection.c index 693e6532..450fe931 100644 --- a/src/settings/plugins/ifnet/nm-ifnet-connection.c +++ b/src/settings/plugins/ifnet/nm-ifnet-connection.c @@ -27,8 +27,8 @@ #include #include #include -#include -#include +#include +#include "nm-default.h" #include "nm-ifnet-connection.h" #include "connection_parser.h" #include "net_parser.h" @@ -50,7 +50,7 @@ static guint signals[IFNET_LAST_SIGNAL] = { 0 }; typedef struct { gchar *conn_name; - NMSystemConfigInterface *config; + NMSettingsPlugin *config; } NMIfnetConnectionPrivate; NMIfnetConnection * @@ -102,8 +102,9 @@ nm_ifnet_connection_get_conn_name (NMIfnetConnection *connection) static void commit_changes (NMSettingsConnection *connection, + NMSettingsConnectionCommitReason commit_reason, NMSettingsConnectionCommitFunc callback, - gpointer user_data) + gpointer user_data) { GError *error = NULL; NMIfnetConnectionPrivate *priv = NM_IFNET_CONNECTION_GET_PRIVATE (connection); @@ -139,7 +140,7 @@ commit_changes (NMSettingsConnection *connection, g_free (priv->conn_name); priv->conn_name = new_name; - NM_SETTINGS_CONNECTION_CLASS (nm_ifnet_connection_parent_class)->commit_changes (connection, callback, user_data); + NM_SETTINGS_CONNECTION_CLASS (nm_ifnet_connection_parent_class)->commit_changes (connection, commit_reason, callback, user_data); nm_log_info (LOGD_SETTINGS, "Successfully updated %s", priv->conn_name); } else { nm_log_warn (LOGD_SETTINGS, "Failed to update %s", diff --git a/src/settings/plugins/ifnet/plugin.c b/src/settings/plugins/ifnet/plugin.c index 5eab31ab..b670cdac 100644 --- a/src/settings/plugins/ifnet/plugin.c +++ b/src/settings/plugins/ifnet/plugin.c @@ -25,17 +25,16 @@ #include #include -#include -#include #include #include +#include "nm-default.h" #include "nm-dbus-interface.h" -#include "nm-system-config-interface.h" -#include "nm-logging.h" +#include "nm-settings-plugin.h" #include "nm-ifnet-connection.h" #include "nm-config.h" +#include "NetworkManagerUtils.h" #include "plugin.h" #include "net_utils.h" @@ -45,19 +44,16 @@ #define IFNET_PLUGIN_NAME_PRINT "ifnet" #define IFNET_PLUGIN_INFO "(C) 1999-2010 Gentoo Foundation, Inc. To report bugs please use bugs.gentoo.org with [networkmanager] or [qiaomuf] prefix." -#define IFNET_SYSTEM_HOSTNAME_FILE "/etc/conf.d/hostname" #define IFNET_MANAGE_WELL_KNOWN_DEFAULT TRUE typedef struct { GHashTable *connections; /* uuid::connection */ - gchar *hostname; gboolean unmanaged_well_known; - GFileMonitor *hostname_monitor; GFileMonitor *net_monitor; GFileMonitor *wpa_monitor; -} SCPluginIfnetPrivate; +} SettingsPluginIfnetPrivate; typedef void (*FileChangedFn) (gpointer user_data); @@ -66,56 +62,17 @@ typedef struct { gpointer user_data; } FileMonitorInfo; -static void system_config_interface_init (NMSystemConfigInterface *class); +static void settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface); -static void reload_connections (NMSystemConfigInterface *config); +static void reload_connections (NMSettingsPlugin *config); -G_DEFINE_TYPE_EXTENDED (SCPluginIfnet, sc_plugin_ifnet, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, system_config_interface_init)) -#define SC_PLUGIN_IFNET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_IFNET, SCPluginIfnetPrivate)) -/* -static void -ignore_cb(NMSettingsConnectionInterface * connection, - GError * error, gpointer user_data) -{ -} -*/ -static const char * -get_hostname (NMSystemConfigInterface * config) -{ - return SC_PLUGIN_IFNET_GET_PRIVATE (config)->hostname; -} - -static void -update_system_hostname (gpointer config) -{ - SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (config); - - if (priv->hostname) - g_free (priv->hostname); - priv->hostname = read_hostname (IFNET_SYSTEM_HOSTNAME_FILE); +G_DEFINE_TYPE_EXTENDED (SettingsPluginIfnet, settings_plugin_ifnet, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN, + settings_plugin_interface_init)) +#define SETTINGS_PLUGIN_IFNET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SETTINGS_TYPE_PLUGIN_IFNET, SettingsPluginIfnetPrivate)) - g_object_notify (G_OBJECT (config), - NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); - nm_log_info (LOGD_SETTINGS, "Hostname updated to: %s", priv->hostname); -} - -static void -write_system_hostname (NMSystemConfigInterface * config, - const gchar * newhostname) -{ - SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (config); - - g_return_if_fail (newhostname); - nm_log_info (LOGD_SETTINGS, "Write system hostname: %s", newhostname); - if (write_hostname (IFNET_SYSTEM_HOSTNAME_FILE, newhostname)) { - g_free (priv->hostname); - priv->hostname = g_strdup (newhostname); - g_object_notify (G_OBJECT (config), - NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); - } else - nm_log_warn (LOGD_SETTINGS, "Write system hostname: %s failed", newhostname); -} +static SettingsPluginIfnet *settings_plugin_ifnet_get (void); +NM_DEFINE_SINGLETON_GETTER (SettingsPluginIfnet, settings_plugin_ifnet_get, SETTINGS_TYPE_PLUGIN_IFNET); static gboolean is_managed_plugin (void) @@ -177,12 +134,9 @@ monitor_file_changes (const char *filename, static void setup_monitors (NMIfnetConnection * connection, gpointer user_data) { - SCPluginIfnet *self = SC_PLUGIN_IFNET (user_data); - SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (self); + SettingsPluginIfnet *self = SETTINGS_PLUGIN_IFNET (user_data); + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self); - priv->hostname_monitor = - monitor_file_changes (IFNET_SYSTEM_HOSTNAME_FILE, - update_system_hostname, user_data); if (nm_config_get_monitor_connection_files (nm_config_get ())) { priv->net_monitor = monitor_file_changes (CONF_NET_FILE, (FileChangedFn) reload_connections, @@ -196,13 +150,9 @@ setup_monitors (NMIfnetConnection * connection, gpointer user_data) static void cancel_monitors (NMIfnetConnection * connection, gpointer user_data) { - SCPluginIfnet *self = SC_PLUGIN_IFNET (user_data); - SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (self); + SettingsPluginIfnet *self = SETTINGS_PLUGIN_IFNET (user_data); + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self); - if (priv->hostname_monitor) { - g_file_monitor_cancel (priv->hostname_monitor); - g_object_unref (priv->hostname_monitor); - } if (priv->net_monitor) { g_file_monitor_cancel (priv->net_monitor); g_object_unref (priv->net_monitor); @@ -216,14 +166,14 @@ cancel_monitors (NMIfnetConnection * connection, gpointer user_data) static void connection_removed_cb (NMSettingsConnection *obj, gpointer user_data) { - g_hash_table_remove (SC_PLUGIN_IFNET_GET_PRIVATE (user_data)->connections, + g_hash_table_remove (SETTINGS_PLUGIN_IFNET_GET_PRIVATE (user_data)->connections, nm_connection_get_uuid (NM_CONNECTION (obj))); } static void -track_new_connection (SCPluginIfnet *self, NMIfnetConnection *connection) +track_new_connection (SettingsPluginIfnet *self, NMIfnetConnection *connection) { - g_hash_table_insert (SC_PLUGIN_IFNET_GET_PRIVATE (self)->connections, + g_hash_table_insert (SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self)->connections, g_strdup (nm_connection_get_uuid (NM_CONNECTION (connection))), g_object_ref (connection)); g_signal_connect (connection, NM_SETTINGS_CONNECTION_REMOVED, @@ -232,10 +182,10 @@ track_new_connection (SCPluginIfnet *self, NMIfnetConnection *connection) } static void -reload_connections (NMSystemConfigInterface *config) +reload_connections (NMSettingsPlugin *config) { - SCPluginIfnet *self = SC_PLUGIN_IFNET (config); - SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (self); + SettingsPluginIfnet *self = SETTINGS_PLUGIN_IFNET (config); + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self); GList *conn_names = NULL, *n_iter = NULL; gboolean auto_refresh; GError *error = NULL; @@ -293,7 +243,7 @@ reload_connections (NMSystemConfigInterface *config) nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (old)); track_new_connection (self, new); if (is_managed_plugin () && is_managed (conn_name)) - g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, new); + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, new); } } else { /* Update existing connection with new settings */ @@ -310,11 +260,11 @@ reload_connections (NMSystemConfigInterface *config) nm_log_info (LOGD_SETTINGS, "Connection %s updated", nm_connection_get_id (NM_CONNECTION (new))); } - g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); } else if (new) { track_new_connection (self, new); if (is_managed_plugin () && is_managed (conn_name)) - g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, new); + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, new); } /* Track all valid connections so we can remove deleted ones later */ @@ -341,12 +291,12 @@ reload_connections (NMSystemConfigInterface *config) } static NMSettingsConnection * -add_connection (NMSystemConfigInterface *config, +add_connection (NMSettingsPlugin *config, NMConnection *source, gboolean save_to_disk, GError **error) { - SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (config); + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (config); NMIfnetConnection *new = NULL; /* Ensure we reject attempts to add the connection long before we're @@ -363,7 +313,7 @@ add_connection (NMSystemConfigInterface *config, } else { new = nm_ifnet_connection_new (source, NULL); if (new) { - track_new_connection (SC_PLUGIN_IFNET (config), new); + track_new_connection (SETTINGS_PLUGIN_IFNET (config), new); /* track_new_connection refs 'new' */ g_object_unref (new); } @@ -406,9 +356,9 @@ check_unmanaged (gpointer key, gpointer data, gpointer user_data) } static GSList * -get_unmanaged_specs (NMSystemConfigInterface * config) +get_unmanaged_specs (NMSettingsPlugin * config) { - SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (config); + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (config); GSList *list = NULL; nm_log_info (LOGD_SETTINGS, "getting unmanaged specs..."); @@ -417,10 +367,10 @@ get_unmanaged_specs (NMSystemConfigInterface * config) } static void -init (NMSystemConfigInterface *config) +init (NMSettingsPlugin *config) { - SCPluginIfnet *self = SC_PLUGIN_IFNET (config); - SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (self); + SettingsPluginIfnet *self = SETTINGS_PLUGIN_IFNET (config); + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (self); nm_log_info (LOGD_SETTINGS, "Initializing!"); @@ -431,15 +381,14 @@ init (NMSystemConfigInterface *config) setup_monitors (NULL, config); reload_connections (config); - update_system_hostname (self); nm_log_info (LOGD_SETTINGS, "Initialzation complete!"); } static GSList * -get_connections (NMSystemConfigInterface *config) +get_connections (NMSettingsPlugin *config) { - SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (config); + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (config); GSList *connections = NULL; GHashTableIter iter; NMIfnetConnection *connection; @@ -459,17 +408,17 @@ get_connections (NMSystemConfigInterface *config) } static void -system_config_interface_init (NMSystemConfigInterface *class) +settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) { - class->init = init; - class->get_connections = get_connections; - class->get_unmanaged_specs = get_unmanaged_specs; - class->add_connection = add_connection; - class->reload_connections = reload_connections; + plugin_iface->init = init; + plugin_iface->get_connections = get_connections; + plugin_iface->get_unmanaged_specs = get_unmanaged_specs; + plugin_iface->add_connection = add_connection; + plugin_iface->reload_connections = reload_connections; } static void -sc_plugin_ifnet_init (SCPluginIfnet * plugin) +settings_plugin_ifnet_init (SettingsPluginIfnet * plugin) { } @@ -477,23 +426,16 @@ static void get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - NMSystemConfigInterface *self = NM_SYSTEM_CONFIG_INTERFACE (object); - switch (prop_id) { - case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME: + case NM_SETTINGS_PLUGIN_PROP_NAME: g_value_set_string (value, IFNET_PLUGIN_NAME_PRINT); break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO: + case NM_SETTINGS_PLUGIN_PROP_INFO: g_value_set_string (value, IFNET_PLUGIN_INFO); break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES: + case NM_SETTINGS_PLUGIN_PROP_CAPABILITIES: g_value_set_uint (value, - NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS - | - NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME); - break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME: - g_value_set_string (value, get_hostname (self)); + NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -506,15 +448,6 @@ set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { switch (prop_id) { - case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME:{ - const gchar *hostname = g_value_get_string (value); - - if (hostname && strlen (hostname) < 1) - hostname = NULL; - write_system_hostname (NM_SYSTEM_CONFIG_INTERFACE - (object), hostname); - break; - } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -524,8 +457,8 @@ set_property (GObject * object, guint prop_id, const GValue * value, static void dispose (GObject * object) { - SCPluginIfnet *plugin = SC_PLUGIN_IFNET (object); - SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (plugin); + SettingsPluginIfnet *plugin = SETTINGS_PLUGIN_IFNET (object); + SettingsPluginIfnetPrivate *priv = SETTINGS_PLUGIN_IFNET_GET_PRIVATE (plugin); cancel_monitors (NULL, object); if (priv->connections) { @@ -533,53 +466,37 @@ dispose (GObject * object) priv->connections = NULL; } - g_free (priv->hostname); - priv->hostname = NULL; - ifnet_destroy (); wpa_parser_destroy (); - G_OBJECT_CLASS (sc_plugin_ifnet_parent_class)->dispose (object); + G_OBJECT_CLASS (settings_plugin_ifnet_parent_class)->dispose (object); } static void -sc_plugin_ifnet_class_init (SCPluginIfnetClass * req_class) +settings_plugin_ifnet_class_init (SettingsPluginIfnetClass * req_class) { GObjectClass *object_class = G_OBJECT_CLASS (req_class); - g_type_class_add_private (req_class, sizeof (SCPluginIfnetPrivate)); + g_type_class_add_private (req_class, sizeof (SettingsPluginIfnetPrivate)); object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME, - NM_SYSTEM_CONFIG_INTERFACE_NAME); - - g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, - NM_SYSTEM_CONFIG_INTERFACE_INFO); + NM_SETTINGS_PLUGIN_PROP_NAME, + NM_SETTINGS_PLUGIN_NAME); g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES, - NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES); + NM_SETTINGS_PLUGIN_PROP_INFO, + NM_SETTINGS_PLUGIN_INFO); g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME, - NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); + NM_SETTINGS_PLUGIN_PROP_CAPABILITIES, + NM_SETTINGS_PLUGIN_CAPABILITIES); } G_MODULE_EXPORT GObject * -nm_system_config_factory (void) +nm_settings_plugin_factory (void) { - static SCPluginIfnet *singleton = NULL; - SCPluginIfnetPrivate *priv; - - if (!singleton) { - singleton = SC_PLUGIN_IFNET (g_object_new (SC_TYPE_PLUGIN_IFNET, NULL)); - priv = SC_PLUGIN_IFNET_GET_PRIVATE (singleton); - } else - g_object_ref (singleton); - - return G_OBJECT (singleton); + return g_object_ref (settings_plugin_ifnet_get ()); } diff --git a/src/settings/plugins/ifnet/plugin.h b/src/settings/plugins/ifnet/plugin.h index 6ac0f482..33dcc201 100644 --- a/src/settings/plugins/ifnet/plugin.h +++ b/src/settings/plugins/ifnet/plugin.h @@ -23,25 +23,25 @@ #ifndef _PLUGIN_H_ #define _PLUGIN_H_ -#include +#include "nm-default.h" -#define SC_TYPE_PLUGIN_IFNET (sc_plugin_ifnet_get_type ()) -#define SC_PLUGIN_IFNET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_IFNET, SCPluginIfnet)) -#define SC_PLUGIN_IFNET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_IFNET, SCPluginIfnetClass)) -#define SC_IS_PLUGIN_IFNET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_IFNET)) -#define SC_IS_PLUGIN_IFNET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_PLUGIN_IFNET)) -#define SC_PLUGIN_IFNET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_IFNET, SCPluginIfnetClass)) +#define SETTINGS_TYPE_PLUGIN_IFNET (settings_plugin_ifnet_get_type ()) +#define SETTINGS_PLUGIN_IFNET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SETTINGS_TYPE_PLUGIN_IFNET, SettingsPluginIfnet)) +#define SETTINGS_PLUGIN_IFNET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SETTINGS_TYPE_PLUGIN_IFNET, SettingsPluginIfnetClass)) +#define SETTINGS_IS_PLUGIN_IFNET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SETTINGS_TYPE_PLUGIN_IFNET)) +#define SETTINGS_IS_PLUGIN_IFNET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SETTINGS_TYPE_PLUGIN_IFNET)) +#define SETTINGS_PLUGIN_IFNET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SETTINGS_TYPE_PLUGIN_IFNET, SettingsPluginIfnetClass)) -typedef struct _SCPluginIfnet SCPluginIfnet; -typedef struct _SCPluginIfnetClass SCPluginIfnetClass; +typedef struct _SettingsPluginIfnet SettingsPluginIfnet; +typedef struct _SettingsPluginIfnetClass SettingsPluginIfnetClass; -struct _SCPluginIfnet { +struct _SettingsPluginIfnet { GObject parent; }; -struct _SCPluginIfnetClass { +struct _SettingsPluginIfnetClass { GObjectClass parent; }; -GType sc_plugin_ifnet_get_type (void); +GType settings_plugin_ifnet_get_type (void); #endif diff --git a/src/settings/plugins/ifnet/tests/Makefile.am b/src/settings/plugins/ifnet/tests/Makefile.am index 754bb182..1919f141 100644 --- a/src/settings/plugins/ifnet/tests/Makefile.am +++ b/src/settings/plugins/ifnet/tests/Makefile.am @@ -4,42 +4,43 @@ if ENABLE_TESTS AM_CPPFLAGS= \ -I$(srcdir)/../ \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/settings \ -I$(top_srcdir)/src/platform \ -DG_LOG_DOMAIN=\""NetworkManager-ifnet"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(CHECK_CFLAGS) \ $(GLIB_CFLAGS) \ $(CODE_COVERAGE_CFLAGS) \ + -DTEST_IFNET_DIR=\"$(abs_srcdir)\" \ + -DTEST_SCRATCH_DIR=\"$(abs_builddir)/\" \ -DTEST_WPA_SUPPLICANT_CONF='"$(srcdir)/wpa_supplicant.conf"' \ -DSYSCONFDIR=\"nonexistent\" -noinst_PROGRAMS = check_ifnet -check_ifnet_SOURCES = \ - test_all.c \ +noinst_PROGRAMS = test-ifnet +test_ifnet_SOURCES = \ + test-ifnet.c \ ../connection_parser.c \ ../net_parser.c \ ../net_utils.c \ ../wpa_parser.c -check_ifnet_LDFLAGS = \ +test_ifnet_LDFLAGS = \ $(CODE_COVERAGE_LDFLAGS) -check_ifnet_LDADD = $(top_builddir)/src/libNetworkManager.la +test_ifnet_LDADD = $(top_builddir)/src/libNetworkManager.la -check-local: check_ifnet - $(abs_builddir)/check_ifnet $(abs_srcdir) $(abs_builddir) +#@VALGRIND_RULES@ +TESTS = test-ifnet endif EXTRA_DIST = \ - hostname \ net \ net.all \ nm-system-settings.conf \ diff --git a/src/settings/plugins/ifnet/tests/Makefile.in b/src/settings/plugins/ifnet/tests/Makefile.in index d331ecee..1e08b955 100644 --- a/src/settings/plugins/ifnet/tests/Makefile.in +++ b/src/settings/plugins/ifnet/tests/Makefile.in @@ -88,7 +88,8 @@ PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ -@ENABLE_TESTS_TRUE@noinst_PROGRAMS = check_ifnet$(EXEEXT) +@ENABLE_TESTS_TRUE@noinst_PROGRAMS = test-ifnet$(EXEEXT) +@ENABLE_TESTS_TRUE@TESTS = test-ifnet$(EXEEXT) subdir = src/settings/plugins/ifnet/tests ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ @@ -112,22 +113,22 @@ CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = PROGRAMS = $(noinst_PROGRAMS) -am__check_ifnet_SOURCES_DIST = test_all.c ../connection_parser.c \ +am__test_ifnet_SOURCES_DIST = test-ifnet.c ../connection_parser.c \ ../net_parser.c ../net_utils.c ../wpa_parser.c -@ENABLE_TESTS_TRUE@am_check_ifnet_OBJECTS = test_all.$(OBJEXT) \ +@ENABLE_TESTS_TRUE@am_test_ifnet_OBJECTS = test-ifnet.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ connection_parser.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ net_parser.$(OBJEXT) net_utils.$(OBJEXT) \ @ENABLE_TESTS_TRUE@ wpa_parser.$(OBJEXT) -check_ifnet_OBJECTS = $(am_check_ifnet_OBJECTS) -@ENABLE_TESTS_TRUE@check_ifnet_DEPENDENCIES = \ +test_ifnet_OBJECTS = $(am_test_ifnet_OBJECTS) +@ENABLE_TESTS_TRUE@test_ifnet_DEPENDENCIES = \ @ENABLE_TESTS_TRUE@ $(top_builddir)/src/libNetworkManager.la 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 = -check_ifnet_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ +test_ifnet_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(check_ifnet_LDFLAGS) $(LDFLAGS) -o $@ + $(test_ifnet_LDFLAGS) $(LDFLAGS) -o $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -162,8 +163,8 @@ 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 = $(check_ifnet_SOURCES) -DIST_SOURCES = $(am__check_ifnet_SOURCES_DIST) +SOURCES = $(test_ifnet_SOURCES) +DIST_SOURCES = $(am__test_ifnet_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -188,8 +189,212 @@ am__define_uniq_tagged_files = \ 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=''; \ + grn=''; \ + lgn=''; \ + blu=''; \ + mgn=''; \ + brg=''; \ + std=''; \ + fi; \ +} +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__recheck_rx = ^[ ]*:recheck:[ ]* +am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* +am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* +# A command that, given a newline-separated list of test names on the +# standard input, print the name of the tests that are to be re-run +# upon "make recheck". +am__list_recheck_tests = $(AWK) '{ \ + recheck = 1; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + { \ + if ((getline line2 < ($$0 ".log")) < 0) \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ + { \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ + { \ + break; \ + } \ + }; \ + if (recheck) \ + print $$0; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# A command that, given a newline-separated list of test names on the +# standard input, create the global log from their .trs and .log files. +am__create_global_log = $(AWK) ' \ +function fatal(msg) \ +{ \ + print "fatal: making $@: " msg | "cat >&2"; \ + exit 1; \ +} \ +function rst_section(header) \ +{ \ + print header; \ + len = length(header); \ + for (i = 1; i <= len; i = i + 1) \ + printf "="; \ + printf "\n\n"; \ +} \ +{ \ + copy_in_global_log = 1; \ + global_test_result = "RUN"; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".trs"); \ + if (line ~ /$(am__global_test_result_rx)/) \ + { \ + sub("$(am__global_test_result_rx)", "", line); \ + sub("[ ]*$$", "", line); \ + global_test_result = line; \ + } \ + else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ + copy_in_global_log = 0; \ + }; \ + if (copy_in_global_log) \ + { \ + rst_section(global_test_result ": " $$0); \ + while ((rc = (getline line < ($$0 ".log"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".log"); \ + print line; \ + }; \ + printf "\n"; \ + }; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# Restructured Text title. +am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } +# Solaris 10 'make', and several other traditional 'make' implementations, +# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it +# by disabling -e (using the XSI extension "set +e") if it's set. +am__sh_e_setup = case $$- in *e*) set +e;; esac +# Default flags passed to test drivers. +am__common_driver_flags = \ + --color-tests "$$am__color_tests" \ + --enable-hard-errors "$$am__enable_hard_errors" \ + --expect-failure "$$am__expect_failure" +# To be inserted before the command running the test. Creates the +# directory for the log if needed. Stores in $dir the directory +# containing $f, in $tst the test, in $log the log. Executes the +# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and +# passes TESTS_ENVIRONMENT. Set up options for the wrapper that +# will run the test scripts (or their associated LOG_COMPILER, if +# thy have one). +am__check_pre = \ +$(am__sh_e_setup); \ +$(am__vpath_adj_setup) $(am__vpath_adj) \ +$(am__tty_colors); \ +srcdir=$(srcdir); export srcdir; \ +case "$@" in \ + */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ + *) am__odir=.;; \ +esac; \ +test "x$$am__odir" = x"." || test -d "$$am__odir" \ + || $(MKDIR_P) "$$am__odir" || exit $$?; \ +if test -f "./$$f"; then dir=./; \ +elif test -f "$$f"; then dir=; \ +else dir="$(srcdir)/"; fi; \ +tst=$$dir$$f; log='$@'; \ +if test -n '$(DISABLE_HARD_ERRORS)'; then \ + am__enable_hard_errors=no; \ +else \ + am__enable_hard_errors=yes; \ +fi; \ +case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ + am__expect_failure=yes;; \ + *) \ + am__expect_failure=no;; \ +esac; \ +$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) +# A shell command to get the names of the tests scripts with any registered +# extension removed (i.e., equivalently, the names of the test logs, with +# the '.log' extension removed). The result is saved in the shell variable +# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, +# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", +# since that might cause problem with VPATH rewrites for suffix-less tests. +# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. +am__set_TESTS_bases = \ + bases='$(TEST_LOGS)'; \ + bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ + bases=`echo $$bases` +RECHECK_LOGS = $(TEST_LOGS) +AM_RECURSIVE_TARGETS = check recheck +TEST_SUITE_LOG = test-suite.log +TEST_EXTENSIONS = @EXEEXT@ .test +LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) +am__set_b = \ + case '$@' in \ + */*) \ + case '$*' in \ + */*) b='$*';; \ + *) b=`echo '$@' | sed 's/\.log$$//'`; \ + esac;; \ + *) \ + b='$*';; \ + esac +am__test_logs1 = $(TESTS:=.log) +am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) +TEST_LOGS = $(am__test_logs2:.test.log=.log) +TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver +TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ + $(TEST_LOG_FLAGS) am__DIST_COMMON = $(srcdir)/Makefile.in \ - $(top_srcdir)/build-aux/depcomp + $(top_srcdir)/build-aux/depcomp \ + $(top_srcdir)/build-aux/test-driver DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALL_LINGUAS = @ALL_LINGUAS@ @@ -206,7 +411,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -218,8 +422,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -229,6 +431,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -283,16 +486,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -329,6 +529,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -357,7 +559,6 @@ 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@ @@ -372,6 +573,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -432,6 +635,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -439,6 +643,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -456,35 +661,36 @@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ @ENABLE_TESTS_TRUE@AM_CPPFLAGS = \ @ENABLE_TESTS_TRUE@ -I$(srcdir)/../ \ -@ENABLE_TESTS_TRUE@ -I$(top_srcdir)/include \ -@ENABLE_TESTS_TRUE@ -I$(top_builddir)/include \ +@ENABLE_TESTS_TRUE@ -I$(top_srcdir)/shared \ +@ENABLE_TESTS_TRUE@ -I$(top_builddir)/shared \ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/libnm-core \ @ENABLE_TESTS_TRUE@ -I$(top_builddir)/libnm-core \ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/src \ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/src/settings \ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/src/platform \ @ENABLE_TESTS_TRUE@ -DG_LOG_DOMAIN=\""NetworkManager-ifnet"\" \ -@ENABLE_TESTS_TRUE@ -DNETWORKMANAGER_COMPILATION \ +@ENABLE_TESTS_TRUE@ -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ @ENABLE_TESTS_TRUE@ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ @ENABLE_TESTS_TRUE@ $(CHECK_CFLAGS) \ @ENABLE_TESTS_TRUE@ $(GLIB_CFLAGS) \ @ENABLE_TESTS_TRUE@ $(CODE_COVERAGE_CFLAGS) \ +@ENABLE_TESTS_TRUE@ -DTEST_IFNET_DIR=\"$(abs_srcdir)\" \ +@ENABLE_TESTS_TRUE@ -DTEST_SCRATCH_DIR=\"$(abs_builddir)/\" \ @ENABLE_TESTS_TRUE@ -DTEST_WPA_SUPPLICANT_CONF='"$(srcdir)/wpa_supplicant.conf"' \ @ENABLE_TESTS_TRUE@ -DSYSCONFDIR=\"nonexistent\" -@ENABLE_TESTS_TRUE@check_ifnet_SOURCES = \ -@ENABLE_TESTS_TRUE@ test_all.c \ +@ENABLE_TESTS_TRUE@test_ifnet_SOURCES = \ +@ENABLE_TESTS_TRUE@ test-ifnet.c \ @ENABLE_TESTS_TRUE@ ../connection_parser.c \ @ENABLE_TESTS_TRUE@ ../net_parser.c \ @ENABLE_TESTS_TRUE@ ../net_utils.c \ @ENABLE_TESTS_TRUE@ ../wpa_parser.c -@ENABLE_TESTS_TRUE@check_ifnet_LDFLAGS = \ +@ENABLE_TESTS_TRUE@test_ifnet_LDFLAGS = \ @ENABLE_TESTS_TRUE@ $(CODE_COVERAGE_LDFLAGS) -@ENABLE_TESTS_TRUE@check_ifnet_LDADD = $(top_builddir)/src/libNetworkManager.la +@ENABLE_TESTS_TRUE@test_ifnet_LDADD = $(top_builddir)/src/libNetworkManager.la EXTRA_DIST = \ - hostname \ net \ net.all \ nm-system-settings.conf \ @@ -494,7 +700,7 @@ EXTRA_DIST = \ all: all-am .SUFFIXES: -.SUFFIXES: .c .lo .o .obj +.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ @@ -534,9 +740,9 @@ clean-noinstPROGRAMS: echo " rm -f" $$list; \ rm -f $$list -check_ifnet$(EXEEXT): $(check_ifnet_OBJECTS) $(check_ifnet_DEPENDENCIES) $(EXTRA_check_ifnet_DEPENDENCIES) - @rm -f check_ifnet$(EXEEXT) - $(AM_V_CCLD)$(check_ifnet_LINK) $(check_ifnet_OBJECTS) $(check_ifnet_LDADD) $(LIBS) +test-ifnet$(EXEEXT): $(test_ifnet_OBJECTS) $(test_ifnet_DEPENDENCIES) $(EXTRA_test_ifnet_DEPENDENCIES) + @rm -f test-ifnet$(EXEEXT) + $(AM_V_CCLD)$(test_ifnet_LINK) $(test_ifnet_OBJECTS) $(test_ifnet_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -547,7 +753,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/connection_parser.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_parser.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net_utils.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_all.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-ifnet.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wpa_parser.Po@am__quote@ .c.o: @@ -685,6 +891,169 @@ cscopelist-am: $(am__tagged_files) distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +# Recover from deleted '.trs' file; this should ensure that +# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create +# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells +# to avoid problems with "make -n". +.log.trs: + rm -f $< $@ + $(MAKE) $(AM_MAKEFLAGS) $< + +# Leading 'am--fnord' is there to ensure the list of targets does not +# expand to empty, as could happen e.g. with make check TESTS=''. +am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) +am--force-recheck: + @: + +$(TEST_SUITE_LOG): $(TEST_LOGS) + @$(am__set_TESTS_bases); \ + am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ + redo_bases=`for i in $$bases; do \ + am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ + done`; \ + if test -n "$$redo_bases"; then \ + redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ + redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ + if $(am__make_dryrun); then :; else \ + rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ + fi; \ + fi; \ + if test -n "$$am__remaking_logs"; then \ + echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ + "recursion detected" >&2; \ + elif test -n "$$redo_logs"; then \ + am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ + fi; \ + if $(am__make_dryrun); then :; else \ + st=0; \ + errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ + for i in $$redo_bases; do \ + test -f $$i.trs && test -r $$i.trs \ + || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ + test -f $$i.log && test -r $$i.log \ + || { echo "$$errmsg $$i.log" >&2; st=1; }; \ + done; \ + test $$st -eq 0 || exit 1; \ + fi + @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ + ws='[ ]'; \ + results=`for b in $$bases; do echo $$b.trs; done`; \ + test -n "$$results" || results=/dev/null; \ + all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ + pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ + fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ + skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ + xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ + xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ + error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ + if test `expr $$fail + $$xpass + $$error` -eq 0; then \ + success=true; \ + else \ + success=false; \ + fi; \ + br='==================='; br=$$br$$br$$br$$br; \ + result_count () \ + { \ + if test x"$$1" = x"--maybe-color"; then \ + maybe_colorize=yes; \ + elif test x"$$1" = x"--no-color"; then \ + maybe_colorize=no; \ + else \ + echo "$@: invalid 'result_count' usage" >&2; exit 4; \ + fi; \ + shift; \ + desc=$$1 count=$$2; \ + if test $$maybe_colorize = yes && test $$count -gt 0; then \ + color_start=$$3 color_end=$$std; \ + else \ + color_start= color_end=; \ + fi; \ + echo "$${color_start}# $$desc $$count$${color_end}"; \ + }; \ + create_testsuite_report () \ + { \ + result_count $$1 "TOTAL:" $$all "$$brg"; \ + result_count $$1 "PASS: " $$pass "$$grn"; \ + result_count $$1 "SKIP: " $$skip "$$blu"; \ + result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ + result_count $$1 "FAIL: " $$fail "$$red"; \ + result_count $$1 "XPASS:" $$xpass "$$red"; \ + result_count $$1 "ERROR:" $$error "$$mgn"; \ + }; \ + { \ + echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ + $(am__rst_title); \ + create_testsuite_report --no-color; \ + echo; \ + echo ".. contents:: :depth: 2"; \ + echo; \ + for b in $$bases; do echo $$b; done \ + | $(am__create_global_log); \ + } >$(TEST_SUITE_LOG).tmp || exit 1; \ + mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ + if $$success; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ + fi; \ + echo "$${col}$$br$${std}"; \ + echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ + echo "$${col}$$br$${std}"; \ + create_testsuite_report --maybe-color; \ + echo "$$col$$br$$std"; \ + if $$success; then :; else \ + echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ + if test -n "$(PACKAGE_BUGREPORT)"; then \ + echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ + fi; \ + echo "$$col$$br$$std"; \ + fi; \ + $$success || exit 1 + +check-TESTS: + @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list + @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + trs_list=`for i in $$bases; do echo $$i.trs; done`; \ + log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ + exit $$?; +recheck: all + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + bases=`for i in $$bases; do echo $$i; done \ + | $(am__list_recheck_tests)` || exit 1; \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + log_list=`echo $$log_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ + am__force_recheck=am--force-recheck \ + TEST_LOGS="$$log_list"; \ + exit $$? +test-ifnet.log: test-ifnet$(EXEEXT) + @p='test-ifnet$(EXEEXT)'; \ + b='test-ifnet'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +.test.log: + @p='$<'; \ + $(am__set_b); \ + $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +@am__EXEEXT_TRUE@.test$(EXEEXT).log: +@am__EXEEXT_TRUE@ @p='$<'; \ +@am__EXEEXT_TRUE@ $(am__set_b); \ +@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ +@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ +@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ +@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) + distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ @@ -715,9 +1084,8 @@ distdir: $(DISTFILES) || exit 1; \ fi; \ done -@ENABLE_TESTS_FALSE@check-local: check-am: all-am - $(MAKE) $(AM_MAKEFLAGS) check-local + $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: check-am all-am: Makefile $(PROGRAMS) installdirs: @@ -741,6 +1109,9 @@ install-strip: "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: + -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) + -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) + -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) clean-generic: @@ -824,7 +1195,7 @@ uninstall-am: .MAKE: check-am install-am install-strip -.PHONY: CTAGS GTAGS TAGS all all-am check check-am check-local clean \ +.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 \ @@ -836,16 +1207,13 @@ uninstall-am: 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 + recheck tags tags-am uninstall uninstall-am .PRECIOUS: Makefile @ENABLE_TESTS_TRUE@@GNOME_CODE_COVERAGE_RULES@ -@ENABLE_TESTS_TRUE@check-local: check_ifnet -@ENABLE_TESTS_TRUE@ $(abs_builddir)/check_ifnet $(abs_srcdir) $(abs_builddir) - # 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/settings/plugins/ifnet/tests/hostname b/src/settings/plugins/ifnet/tests/hostname deleted file mode 100644 index 25c76165..00000000 --- a/src/settings/plugins/ifnet/tests/hostname +++ /dev/null @@ -1,2 +0,0 @@ -#Generated by NetworkManager -hostname="gentoo" diff --git a/src/settings/plugins/ifnet/tests/test-ifnet.c b/src/settings/plugins/ifnet/tests/test-ifnet.c new file mode 100644 index 00000000..96fb5dd3 --- /dev/null +++ b/src/settings/plugins/ifnet/tests/test-ifnet.c @@ -0,0 +1,398 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service (ifnet) + * + * Mu Qiao + * + * 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) 1999-2010 Gentoo Foundation, Inc. + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "nm-default.h" +#include "nm-linux-platform.h" + +#include "net_parser.h" +#include "net_utils.h" +#include "wpa_parser.h" +#include "connection_parser.h" +#include "nm-config.h" + +#include "nm-test-utils.h" + +/* Fake NMConfig handling; the values it returns don't matter, so this + * is easier than forcing it to read our own config file, etc. + */ +NMConfig * +nm_config_get (void) +{ + return NULL; +} + +const char * +nm_config_get_dhcp_client (NMConfig *config) +{ + return "dhclient"; +} + +static void +test_getdata (void) +{ + g_assert (ifnet_get_data ("eth1", "config") && + strcmp (ifnet_get_data ("eth1", "config"), "( \"dhcp\" )") == 0); + g_assert (ifnet_get_data ("ppp0", "username") && + strcmp (ifnet_get_data ("ppp0", "username"), "user") == 0); + g_assert (ifnet_get_data ("ppp0", "password") && + strcmp (ifnet_get_data ("ppp0", "password"), "password") == 0); + g_assert (ifnet_get_global_data ("modules") && + strcmp ("!wpa_supplicant", ifnet_get_global_data ("modules")) == 0); +} + +static void +test_is_static (void) +{ + g_assert (!is_static_ip4 ("eth1")); + g_assert (is_static_ip4 ("eth0")); + g_assert (!is_static_ip6 ("eth0")); +} + +static void +test_has_default_route (void) +{ + g_assert (has_default_ip4_route ("eth0")); + g_assert (has_default_ip6_route ("eth4")); + g_assert (!has_default_ip4_route ("eth5") && + !has_default_ip6_route ("eth5")); +} + +static void +test_has_ip6_address (void) +{ + g_assert (has_ip6_address ("eth2")); + g_assert (!has_ip6_address ("eth0")); +} + +static void +test_is_ip4_address (void) +{ + gchar *address1 = "192.168.4.232/24"; + gchar *address2 = "192.168.100.{1..254}/24"; + gchar *address3 = "192.168.4.2555/24"; + + g_assert (is_ip4_address (address1)); + g_assert (is_ip4_address (address2)); + g_assert (!is_ip4_address (address3)); +} + +static void +test_is_ip6_address (void) +{ + gchar *address1 = "4321:0:1:2:3:4:567:89ac/24"; + + g_assert (is_ip6_address (address1)); +} + +static void +check_ip_block (ip_block * iblock, gchar * ip, guint32 prefix, gchar * gateway) +{ + g_assert_cmpstr (ip, ==, iblock->ip); + g_assert (prefix == iblock->prefix); + g_assert_cmpstr (gateway, ==, iblock->next_hop); +} + +static void +test_convert_ipv4_config_block (void) +{ + ip_block *iblock = convert_ip4_config_block ("eth0"); + ip_block *tmp = iblock; + + g_assert (iblock != NULL); + check_ip_block (iblock, "202.117.16.121", 24, "202.117.16.1"); + iblock = iblock->next; + destroy_ip_block (tmp); + g_assert (iblock != NULL); + check_ip_block (iblock, "192.168.4.121", 24, "202.117.16.1"); + destroy_ip_block (iblock); + + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, + "*Can't handle IPv4 address*202.117.16.1211*"); + iblock = convert_ip4_config_block ("eth2"); + g_test_assert_expected_messages (); + g_assert (iblock != NULL && iblock->next == NULL); + check_ip_block (iblock, "192.168.4.121", 24, NULL); + destroy_ip_block (iblock); + + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, + "*missing netmask or prefix*"); + iblock = convert_ip4_config_block ("eth3"); + g_assert (iblock == NULL); +} + +static void +test_convert_ipv4_routes_block (void) +{ + ip_block *iblock = convert_ip4_routes_block ("eth0"); + ip_block *tmp = iblock; + + g_assert (iblock != NULL); + check_ip_block (iblock, "192.168.4.0", 24, "192.168.4.1"); + iblock = iblock->next; + destroy_ip_block (tmp); + g_assert (iblock == NULL); + + iblock = convert_ip4_routes_block ("eth9"); + tmp = iblock; + + g_assert (iblock != NULL); + check_ip_block (iblock, "10.0.0.0", 8, "192.168.0.1"); + iblock = iblock->next; + destroy_ip_block (tmp); + g_assert (iblock == NULL); +} + +static void +test_wpa_parser (void) +{ + const char *value; + + g_assert (exist_ssid ("example")); + + g_assert (exist_ssid ("static-wep-test")); + value = wpa_get_value ("static-wep-test", "key_mgmt"); + g_assert_cmpstr (value, ==, "NONE"); + value = wpa_get_value ("static-wep-test", "wep_key0"); + g_assert_cmpstr (value, ==, "\"abcde\""); + + g_assert (exist_ssid ("leap-example")); + + value = wpa_get_value ("test-with-hash-in-psk", "psk"); + g_assert_cmpstr (value, ==, "\"xjtudlc3731###asdfasdfasdf\""); +} + +static void +test_strip_string (void) +{ + gchar *str = "( \"default via 202.117.16.1\" )"; + gchar *result = g_strdup (str); + gchar *result_b = result; + + result = strip_string (result, '('); + result = strip_string (result, ')'); + result = strip_string (result, '"'); + g_assert_cmpstr (result, ==, "default via 202.117.16.1"); + g_free (result_b); +} + +static void +test_is_unmanaged (void) +{ + g_assert (is_managed ("eth0")); + g_assert (!is_managed ("eth4")); +} + +static void +test_new_connection (void) +{ + GError *error = NULL; + NMConnection *connection; + + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, + "*Can't handle IPv4 address*202.117.16.1211*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, + "*Can't handle IPv6 address*202.117.16.1211*"); + connection = ifnet_update_connection_from_config_block ("eth2", NULL, &error); + g_test_assert_expected_messages (); + g_assert (connection != NULL); + g_object_unref (connection); + + connection = ifnet_update_connection_from_config_block ("qiaomuf", NULL, &error); + g_assert (connection != NULL); + g_object_unref (connection); + + connection = ifnet_update_connection_from_config_block ("myxjtu2", NULL, &error); + g_assert (connection != NULL); + g_object_unref (connection); + + connection = ifnet_update_connection_from_config_block ("eth9", NULL, &error); + g_assert (connection != NULL); + g_object_unref (connection); + + connection = ifnet_update_connection_from_config_block ("eth10", NULL, &error); + g_assert (connection != NULL); + g_object_unref (connection); +} + +static void +kill_backup (char **path) +{ + if (path) { + unlink (*path); + g_free (*path); + *path = NULL; + } +} + +#define NET_GEN_NAME "net.generate" +#define SUP_GEN_NAME "wpa_supplicant.conf.generate" + +static void +test_update_connection (void) +{ + GError *error = NULL; + NMConnection *connection; + gboolean success; + char *backup = NULL; + char *basepath = TEST_IFNET_DIR; + + connection = ifnet_update_connection_from_config_block ("eth0", basepath, &error); + g_assert (connection != NULL); + + success = ifnet_update_parsers_by_connection (connection, "eth0", + NET_GEN_NAME, + SUP_GEN_NAME, + NULL, + &backup, + &error); + kill_backup (&backup); + g_assert (success); + g_object_unref (connection); + + connection = ifnet_update_connection_from_config_block ("0xab3ace", basepath, &error); + g_assert (connection != NULL); + + success = ifnet_update_parsers_by_connection (connection, "0xab3ace", + NET_GEN_NAME, + SUP_GEN_NAME, + NULL, + &backup, + &error); + kill_backup (&backup); + g_assert (success); + g_object_unref (connection); + + unlink (NET_GEN_NAME); + unlink (SUP_GEN_NAME); +} + +static void +test_add_connection (void) +{ + NMConnection *connection; + char *backup = NULL; + const char *basepath = TEST_IFNET_DIR; + + connection = ifnet_update_connection_from_config_block ("eth0", basepath, NULL); + g_assert (ifnet_add_new_connection (connection, NET_GEN_NAME, SUP_GEN_NAME, NULL, &backup, NULL)); + kill_backup (&backup); + g_object_unref (connection); + + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, + "*Can't handle ipv4 address: brd, missing netmask or prefix*"); + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, + "*Can't handle ipv4 address: 202.117.16.255, missing netmask or prefix*"); + connection = ifnet_update_connection_from_config_block ("myxjtu2", basepath, NULL); + g_test_assert_expected_messages (); + g_assert (ifnet_add_new_connection (connection, NET_GEN_NAME, SUP_GEN_NAME, NULL, &backup, NULL)); + kill_backup (&backup); + g_object_unref (connection); + + unlink (NET_GEN_NAME); + unlink (SUP_GEN_NAME); +} + +static void +test_delete_connection (void) +{ + GError *error = NULL; + NMConnection *connection; + char *backup = NULL; + + connection = ifnet_update_connection_from_config_block ("eth7", NULL, &error); + g_assert (connection != NULL); + g_assert (ifnet_delete_connection_in_parsers ("eth7", NET_GEN_NAME, SUP_GEN_NAME, &backup)); + kill_backup (&backup); + g_object_unref (connection); + + connection = ifnet_update_connection_from_config_block ("qiaomuf", NULL, &error); + g_assert (connection != NULL); + g_assert (ifnet_delete_connection_in_parsers ("qiaomuf", NET_GEN_NAME, SUP_GEN_NAME, &backup)); + kill_backup (&backup); + g_object_unref (connection); + + unlink (NET_GEN_NAME); + unlink (SUP_GEN_NAME); +} + +static void +test_missing_config (void) +{ + GError *error = NULL; + NMConnection *connection; + + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, + "*Unknown config for eth8*"); + connection = ifnet_update_connection_from_config_block ("eth8", NULL, &error); + g_test_assert_expected_messages (); + g_assert (connection == NULL && error != NULL); +} + +NMTST_DEFINE (); + +#define TPATH "/settings/plugins/ifnet/" + +int +main (int argc, char **argv) +{ + int ret; + + nm_linux_platform_setup (); + + nmtst_init_assert_logging (&argc, &argv, "WARN", "DEFAULT"); + + ifnet_init (TEST_IFNET_DIR "/net"); + wpa_parser_init (TEST_IFNET_DIR "/wpa_supplicant.conf"); + + g_test_add_func (TPATH "strip-string", test_strip_string); + g_test_add_func (TPATH "is-static", test_is_static); + g_test_add_func (TPATH "has-ip6-address", test_has_ip6_address); + g_test_add_func (TPATH "has-default-route", test_has_default_route); + g_test_add_func (TPATH "get-data", test_getdata); + g_test_add_func (TPATH "is-ip4-address", test_is_ip4_address); + g_test_add_func (TPATH "is-ip6-address", test_is_ip6_address); + g_test_add_func (TPATH "convert-ip4-config", test_convert_ipv4_config_block); + g_test_add_func (TPATH "convert-ip4-routes", test_convert_ipv4_routes_block); + g_test_add_func (TPATH "is-unmanaged", test_is_unmanaged); + g_test_add_func (TPATH "wpa-parser", test_wpa_parser); + g_test_add_func (TPATH "new-connection", test_new_connection); + g_test_add_func (TPATH "update-connection", test_update_connection); + g_test_add_func (TPATH "add-connection", test_add_connection); + g_test_add_func (TPATH "delete-connection", test_delete_connection); + g_test_add_func (TPATH "missing-config", test_missing_config); + + ret = g_test_run (); + + ifnet_destroy (); + wpa_parser_destroy (); + + return ret; +} diff --git a/src/settings/plugins/ifnet/tests/test_all.c b/src/settings/plugins/ifnet/tests/test_all.c deleted file mode 100644 index 55e7e283..00000000 --- a/src/settings/plugins/ifnet/tests/test_all.c +++ /dev/null @@ -1,488 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service (ifnet) - * - * Mu Qiao - * - * 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) 1999-2010 Gentoo Foundation, Inc. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "nm-linux-platform.h" -#include "nm-logging.h" - -#include "net_parser.h" -#include "net_utils.h" -#include "wpa_parser.h" -#include "connection_parser.h" -#include "nm-config.h" - -#include "nm-test-utils.h" - -/* Fake NMConfig handling; the values it returns don't matter, so this - * is easier than forcing it to read our own config file, etc. - */ -NMConfig * -nm_config_get (void) -{ - return NULL; -} - -const char * -nm_config_get_dhcp_client (NMConfig *config) -{ - return "dhclient"; -} - -static void -test_getdata (void) -{ - ASSERT (ifnet_get_data ("eth1", "config") - && strcmp (ifnet_get_data ("eth1", "config"), "( \"dhcp\" )") == 0, - "get data", "config_eth1 is not correct"); - ASSERT (ifnet_get_data ("ppp0", "username") - && strcmp (ifnet_get_data ("ppp0", "username"), "user") == 0, - "get data", "config_ppp0 username is not correctly read"); - ASSERT (ifnet_get_data ("ppp0", "password") - && strcmp (ifnet_get_data ("ppp0", "password"), - "password") == 0, "get data", - "config_ppp0 password is not correctly read"); - ASSERT (ifnet_get_global_data ("modules") - && strcmp ("!wpa_supplicant", ifnet_get_global_data ("modules")) == 0, - "get data", "config_eth1 is not correct"); -} - -static void -test_read_hostname (const char *base_path) -{ - char *hostname_path, *hostname; - - hostname_path = g_build_filename (base_path, "hostname", NULL); - hostname = read_hostname (hostname_path); - - g_assert_cmpstr (hostname, ==, "gentoo"); - - g_free (hostname); - g_free (hostname_path); -} - -static void -test_write_hostname (const char *temp_path) -{ - char *hostname_path, *hostname; - - hostname_path = g_build_filename (temp_path, "hostname-test", NULL); - write_hostname (hostname_path, "gentoo-nm"); - hostname = read_hostname (hostname_path); - - g_assert_cmpstr (hostname, ==, "gentoo-nm"); - - g_free (hostname); - unlink (hostname_path); - g_free (hostname_path); -} - -static void -test_is_static (void) -{ - ASSERT (is_static_ip4 ("eth1") == FALSE, "is static", - "a dhcp interface is recognized as static"); - ASSERT (is_static_ip4 ("eth0") == TRUE, "is static", - "a static interface is recognized as dhcp"); - ASSERT (is_static_ip6 ("eth0") == FALSE, "is static", - "a dhcp interface is recognized as static"); -} - -static void -test_has_default_route (void) -{ - ASSERT (has_default_ip4_route ("eth0"), - "has default route", "eth0 should have a default ipv4 route"); - ASSERT (has_default_ip6_route ("eth4"), - "has default route", "eth4 should have a default ipv6 route"); - ASSERT (!has_default_ip4_route ("eth5") - && !has_default_ip6_route ("eth5"), - "has default route", "eth5 shouldn't have a default route"); -} - -static void -test_has_ip6_address (void) -{ - ASSERT (has_ip6_address ("eth2"), "has ip6 address", - "eth2 should have a ipv6 address"); - ASSERT (!has_ip6_address ("eth0"), "has ip6 address", - "eth0 shouldn't have a ipv6 address") - -} - -static void -test_is_ip4_address (void) -{ - gchar *address1 = "192.168.4.232/24"; - gchar *address2 = "192.168.100.{1..254}/24"; - gchar *address3 = "192.168.4.2555/24"; - - ASSERT (is_ip4_address (address1), "is ip4 address", - "%s should be a valid address", address1); - ASSERT (is_ip4_address (address2), "is ip4 address", - "%s should be a valid address", address2); - ASSERT (!is_ip4_address (address3), "is ip4 address", - "%s should be an invalid address", address3); -} - -static void -test_is_ip6_address (void) -{ - gchar *address1 = "4321:0:1:2:3:4:567:89ac/24"; - - ASSERT (is_ip6_address (address1), "is ip6 address", - "%s should be a valid address", address1); -} - -static void -check_ip_block (ip_block * iblock, gchar * ip, guint32 prefix, gchar * gateway) -{ - ASSERT (strcmp (ip, iblock->ip) == 0, "check ip", - "ip expected:%s, find:%s", ip, iblock->ip); - ASSERT (prefix == iblock->prefix, "check netmask", - "prefix expected:%d, find:%d", prefix, iblock->prefix); - ASSERT (g_strcmp0 (gateway, iblock->next_hop) == 0, "check gateway", - "gateway expected:%s, find:%s", gateway, iblock->next_hop); -} - -static void -test_convert_ipv4_config_block (void) -{ - ip_block *iblock = convert_ip4_config_block ("eth0"); - ip_block *tmp = iblock; - - ASSERT (iblock != NULL, "convert ipv4 block", - "block eth0 should not be NULL"); - check_ip_block (iblock, "202.117.16.121", 24, "202.117.16.1"); - iblock = iblock->next; - destroy_ip_block (tmp); - ASSERT (iblock != NULL, "convert ipv4 block", - "block eth0 should have a second IP address"); - check_ip_block (iblock, "192.168.4.121", 24, "202.117.16.1"); - destroy_ip_block (iblock); - - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, - "*Can't handle IPv4 address*202.117.16.1211*"); - iblock = convert_ip4_config_block ("eth2"); - g_test_assert_expected_messages (); - ASSERT (iblock != NULL - && iblock->next == NULL, - "convert error IPv4 address", "should only get one address"); - check_ip_block (iblock, "192.168.4.121", 24, NULL); - destroy_ip_block (iblock); - - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, - "*missing netmask or prefix*"); - iblock = convert_ip4_config_block ("eth3"); - ASSERT (iblock == NULL, "convert config_block", - "convert error configuration"); -} - -static void -test_convert_ipv4_routes_block (void) -{ - ip_block *iblock = convert_ip4_routes_block ("eth0"); - ip_block *tmp = iblock; - - ASSERT (iblock != NULL, "convert ip4 routes", "should get one route"); - check_ip_block (iblock, "192.168.4.0", 24, "192.168.4.1"); - iblock = iblock->next; - destroy_ip_block (tmp); - ASSERT (iblock == NULL, "convert ip4 routes", - "should only get one route"); - - iblock = convert_ip4_routes_block ("eth9"); - tmp = iblock; - - ASSERT (iblock != NULL, "convert ip4 routes", "should get one route"); - check_ip_block (iblock, "10.0.0.0", 8, "192.168.0.1"); - iblock = iblock->next; - destroy_ip_block (tmp); - ASSERT (iblock == NULL, "convert ip4 routes", - "should only get one route"); -} - -static void -test_wpa_parser (void) -{ - const char *value; - - g_assert (exist_ssid ("example")); - - g_assert (exist_ssid ("static-wep-test")); - value = wpa_get_value ("static-wep-test", "key_mgmt"); - g_assert_cmpstr (value, ==, "NONE"); - value = wpa_get_value ("static-wep-test", "wep_key0"); - g_assert_cmpstr (value, ==, "\"abcde\""); - - g_assert (exist_ssid ("leap-example")); - - value = wpa_get_value ("test-with-hash-in-psk", "psk"); - g_assert_cmpstr (value, ==, "\"xjtudlc3731###asdfasdfasdf\""); -} - -static void -test_strip_string (void) -{ - gchar *str = "( \"default via 202.117.16.1\" )"; - gchar *result = g_strdup (str); - gchar *result_b = result; - - result = strip_string (result, '('); - result = strip_string (result, ')'); - result = strip_string (result, '"'); - ASSERT (strcmp (result, "default via 202.117.16.1") == - 0, "strip_string", - "string isn't stripped, result is: %s", result); - g_free (result_b); -} - -static void -test_is_unmanaged (void) -{ - ASSERT (is_managed ("eth0"), "test_is_unmanaged", - "eth0 should be managed"); - ASSERT (!is_managed ("eth4"), "test_is_unmanaged", - "eth4 should be unmanaged"); -} - -static void -test_new_connection (void) -{ - GError *error = NULL; - NMConnection *connection; - - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, - "*Can't handle IPv4 address*202.117.16.1211*"); - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, - "*Can't handle IPv6 address*202.117.16.1211*"); - connection = ifnet_update_connection_from_config_block ("eth2", NULL, &error); - g_test_assert_expected_messages (); - ASSERT (connection != NULL, "new connection", - "new connection failed: %s", - error ? error->message : "None"); - g_object_unref (connection); - - connection = ifnet_update_connection_from_config_block ("qiaomuf", NULL, &error); - ASSERT (connection != NULL, "new connection", - "new connection failed: %s", - error ? error->message : "NONE"); - g_object_unref (connection); - - connection = ifnet_update_connection_from_config_block ("myxjtu2", NULL, &error); - ASSERT (connection != NULL, "new connection", - "new connection failed: %s", - error ? error->message : "NONE"); - g_object_unref (connection); - - connection = ifnet_update_connection_from_config_block ("eth9", NULL, &error); - ASSERT (connection != NULL, "new connection", - "new connection(eth9) failed: %s", - error ? error->message : "NONE"); - g_object_unref (connection); - - connection = ifnet_update_connection_from_config_block ("eth10", NULL, &error); - ASSERT (connection != NULL, "new connection", - "new connection(eth10) failed: %s", - error ? error->message : "NONE"); - g_object_unref (connection); -} - -static void -kill_backup (char **path) -{ - if (path) { - unlink (*path); - g_free (*path); - *path = NULL; - } -} - -#define NET_GEN_NAME "net.generate" -#define SUP_GEN_NAME "wpa_supplicant.conf.generate" - -static void -test_update_connection (const char *basepath) -{ - GError *error = NULL; - NMConnection *connection; - gboolean success; - char *backup = NULL; - - connection = ifnet_update_connection_from_config_block ("eth0", basepath, &error); - ASSERT (connection != NULL, "get connection", - "get connection failed: %s", - error ? error->message : "None"); - - success = ifnet_update_parsers_by_connection (connection, "eth0", - NET_GEN_NAME, - SUP_GEN_NAME, - NULL, - &backup, - &error); - kill_backup (&backup); - ASSERT (success, "update connection", "update connection failed %s", "eth0"); - g_object_unref (connection); - - connection = ifnet_update_connection_from_config_block ("0xab3ace", basepath, &error); - ASSERT (connection != NULL, "get connection", "get connection failed: %s", - error ? error->message : "None"); - - success = ifnet_update_parsers_by_connection (connection, "0xab3ace", - NET_GEN_NAME, - SUP_GEN_NAME, - NULL, - &backup, - &error); - kill_backup (&backup); - ASSERT (success, "update connection", "update connection failed %s", "0xab3ace"); - g_object_unref (connection); - - unlink (NET_GEN_NAME); - unlink (SUP_GEN_NAME); -} - -static void -test_add_connection (const char *basepath) -{ - NMConnection *connection; - char *backup = NULL; - - connection = ifnet_update_connection_from_config_block ("eth0", basepath, NULL); - ASSERT (ifnet_add_new_connection (connection, NET_GEN_NAME, SUP_GEN_NAME, NULL, &backup, NULL), - "add connection", "add connection failed: %s", "eth0"); - kill_backup (&backup); - g_object_unref (connection); - - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, - "*Can't handle ipv4 address: brd, missing netmask or prefix*"); - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, - "*Can't handle ipv4 address: 202.117.16.255, missing netmask or prefix*"); - connection = ifnet_update_connection_from_config_block ("myxjtu2", basepath, NULL); - g_test_assert_expected_messages (); - ASSERT (ifnet_add_new_connection (connection, NET_GEN_NAME, SUP_GEN_NAME, NULL, &backup, NULL), - "add connection", "add connection failed: %s", "myxjtu2"); - kill_backup (&backup); - g_object_unref (connection); - - unlink (NET_GEN_NAME); - unlink (SUP_GEN_NAME); -} - -static void -test_delete_connection (void) -{ - GError *error = NULL; - NMConnection *connection; - char *backup = NULL; - - connection = ifnet_update_connection_from_config_block ("eth7", NULL, &error); - ASSERT (connection != NULL, "get connection", - "get connection failed: %s", - error ? error->message : "None"); - ASSERT (ifnet_delete_connection_in_parsers ("eth7", NET_GEN_NAME, SUP_GEN_NAME, &backup), - "delete connection", "delete connection failed: %s", "eth7"); - kill_backup (&backup); - g_object_unref (connection); - - connection = ifnet_update_connection_from_config_block ("qiaomuf", NULL, &error); - ASSERT (connection != NULL, "get connection", - "get connection failed: %s", - error ? error->message : "None"); - ASSERT (ifnet_delete_connection_in_parsers ("qiaomuf", NET_GEN_NAME, SUP_GEN_NAME, &backup), - "delete connection", "delete connection failed: %s", "qiaomuf"); - kill_backup (&backup); - g_object_unref (connection); - - unlink (NET_GEN_NAME); - unlink (SUP_GEN_NAME); -} - -static void -test_missing_config (void) -{ - GError *error = NULL; - NMConnection *connection; - - g_test_expect_message ("NetworkManager", G_LOG_LEVEL_WARNING, - "*Unknown config for eth8*"); - connection = ifnet_update_connection_from_config_block ("eth8", NULL, &error); - g_test_assert_expected_messages (); - ASSERT (connection == NULL && error != NULL, "get connection", - "get connection should fail with 'Unknown config for eth8'"); -} - -NMTST_DEFINE (); - -int -main (int argc, char **argv) -{ - char *f; - - nm_linux_platform_setup (); - - nmtst_init_assert_logging (&argc, &argv, "WARN", "DEFAULT"); - - f = g_build_filename (argv[1], "net", NULL); - ifnet_init (f); - g_free (f); - - f = g_build_filename (argv[1], "wpa_supplicant.conf", NULL); - wpa_parser_init (f); - g_free (f); - - test_strip_string (); - test_is_static (); - test_has_ip6_address (); - test_has_default_route (); - test_getdata (); - test_read_hostname (argv[1]); - test_write_hostname (argv[2]); - test_is_ip4_address (); - test_is_ip6_address (); - test_convert_ipv4_config_block (); - test_convert_ipv4_routes_block (); - test_is_unmanaged (); - test_wpa_parser (); - test_convert_ipv4_routes_block (); - test_new_connection (); - test_update_connection (argv[1]); - test_add_connection (argv[1]); - test_delete_connection (); - test_missing_config (); - - ifnet_destroy (); - wpa_parser_destroy (); - - f = g_path_get_basename (argv[0]); - fprintf (stdout, "%s: SUCCESS\n", f); - g_free (f); - return 0; -} diff --git a/src/settings/plugins/ifnet/wpa_parser.c b/src/settings/plugins/ifnet/wpa_parser.c index 3f912da8..9f228d0b 100644 --- a/src/settings/plugins/ifnet/wpa_parser.c +++ b/src/settings/plugins/ifnet/wpa_parser.c @@ -23,8 +23,8 @@ #include #include -#include -#include +#include +#include "nm-default.h" #include "wpa_parser.h" #include "net_parser.h" #include "net_utils.h" diff --git a/src/settings/plugins/ifnet/wpa_parser.h b/src/settings/plugins/ifnet/wpa_parser.h index 3a0d377e..8099d19c 100644 --- a/src/settings/plugins/ifnet/wpa_parser.h +++ b/src/settings/plugins/ifnet/wpa_parser.h @@ -22,7 +22,7 @@ #ifndef _WPA_PARSER_H #define _WPA_PARSER_H -#include +#include "nm-default.h" #define WPA_SUPPLICANT_CONF SYSCONFDIR "/wpa_supplicant/wpa_supplicant.conf" diff --git a/src/settings/plugins/ifupdown/Makefile.am b/src/settings/plugins/ifupdown/Makefile.am index e1f2b339..c5c645d3 100644 --- a/src/settings/plugins/ifupdown/Makefile.am +++ b/src/settings/plugins/ifupdown/Makefile.am @@ -5,12 +5,12 @@ SUBDIRS = . tests AM_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/settings \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-ifupdown"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ $(GUDEV_CFLAGS) \ diff --git a/src/settings/plugins/ifupdown/Makefile.in b/src/settings/plugins/ifupdown/Makefile.in index 3bd19afc..b16c3053 100644 --- a/src/settings/plugins/ifupdown/Makefile.in +++ b/src/settings/plugins/ifupdown/Makefile.in @@ -277,7 +277,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -289,8 +288,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -300,6 +297,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -354,16 +352,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -400,6 +395,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -428,7 +425,6 @@ 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@ @@ -443,6 +439,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -503,6 +501,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -510,6 +509,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -529,12 +529,12 @@ SUBDIRS = . tests AM_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/settings \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-ifupdown"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ $(GUDEV_CFLAGS) \ diff --git a/src/settings/plugins/ifupdown/interface_parser.c b/src/settings/plugins/ifupdown/interface_parser.c index 32d27c57..4606f5ab 100644 --- a/src/settings/plugins/ifupdown/interface_parser.c +++ b/src/settings/plugins/ifupdown/interface_parser.c @@ -29,7 +29,7 @@ #include #include #include "nm-utils.h" -#include "nm-logging.h" +#include "nm-default.h" if_block* first; if_block* last; diff --git a/src/settings/plugins/ifupdown/interface_parser.h b/src/settings/plugins/ifupdown/interface_parser.h index e68abcf6..4034d44c 100644 --- a/src/settings/plugins/ifupdown/interface_parser.h +++ b/src/settings/plugins/ifupdown/interface_parser.h @@ -24,7 +24,7 @@ #ifndef _INTERFACE_PARSER_H #define _INTERFACE_PARSER_H -#include +#include "nm-default.h" typedef struct _if_data { diff --git a/src/settings/plugins/ifupdown/nm-ifupdown-connection.c b/src/settings/plugins/ifupdown/nm-ifupdown-connection.c index c6073bd7..2c8504b0 100644 --- a/src/settings/plugins/ifupdown/nm-ifupdown-connection.c +++ b/src/settings/plugins/ifupdown/nm-ifupdown-connection.c @@ -29,8 +29,8 @@ #include #include #include -#include -#include +#include +#include "nm-default.h" #include "nm-ifupdown-connection.h" #include "parser.h" diff --git a/src/settings/plugins/ifupdown/nm-ifupdown-connection.h b/src/settings/plugins/ifupdown/nm-ifupdown-connection.h index be2ebc0a..54c219f4 100644 --- a/src/settings/plugins/ifupdown/nm-ifupdown-connection.h +++ b/src/settings/plugins/ifupdown/nm-ifupdown-connection.h @@ -25,6 +25,7 @@ #define __NETWORKMANAGER_IFUPDOWN_CONNECTION_H__ #include +#include "nm-default.h" #include "interface_parser.h" G_BEGIN_DECLS diff --git a/src/settings/plugins/ifupdown/parser.c b/src/settings/plugins/ifupdown/parser.c index 15081a4c..8a3d4551 100644 --- a/src/settings/plugins/ifupdown/parser.c +++ b/src/settings/plugins/ifupdown/parser.c @@ -30,8 +30,8 @@ #include #include "nm-core-internal.h" -#include "nm-system-config-interface.h" -#include "nm-logging.h" +#include "nm-settings-plugin.h" +#include "nm-default.h" #include "parser.h" #include "plugin.h" diff --git a/src/settings/plugins/ifupdown/plugin.c b/src/settings/plugins/ifupdown/plugin.c index 8652dd8d..fc361de5 100644 --- a/src/settings/plugins/ifupdown/plugin.c +++ b/src/settings/plugins/ifupdown/plugin.c @@ -25,32 +25,27 @@ #include "config.h" #include -#include - #include -#include -#include -#include #include +#include "nm-default.h" #include "interface_parser.h" #include "nm-dbus-interface.h" -#include "nm-system-config-interface.h" +#include "nm-settings-plugin.h" #include "nm-setting-ip4-config.h" #include "nm-setting-wireless.h" #include "nm-setting-wired.h" #include "nm-setting-ppp.h" #include "nm-utils.h" #include "nm-core-internal.h" +#include "NetworkManagerUtils.h" #include "nm-ifupdown-connection.h" #include "plugin.h" #include "parser.h" -#include "nm-inotify-helper.h" -#include "nm-logging.h" #include "nm-config.h" #include @@ -61,7 +56,6 @@ #define IFUPDOWN_PLUGIN_NAME "ifupdown" #define IFUPDOWN_PLUGIN_INFO "(C) 2008 Canonical Ltd. To report bugs please use the NetworkManager mailing list." -#define IFUPDOWN_SYSTEM_HOSTNAME_FILE "/etc/hostname" #define IFUPDOWN_UNMANAGE_WELL_KNOWN_DEFAULT TRUE @@ -74,7 +68,6 @@ typedef struct { GUdevClient *client; GHashTable *connections; /* /e/n/i block name :: NMIfupdownConnection */ - gchar* hostname; /* Stores all blocks/interfaces read from /e/n/i regardless of whether * there is an NMIfupdownConnection for block. @@ -85,31 +78,31 @@ typedef struct { GHashTable *kernel_ifaces; gboolean unmanage_well_known; - - gulong inotify_event_id; - int inotify_system_hostname_wd; -} SCPluginIfupdownPrivate; +} SettingsPluginIfupdownPrivate; static void -system_config_interface_init (NMSystemConfigInterface *system_config_interface_class); +settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface); + +G_DEFINE_TYPE_EXTENDED (SettingsPluginIfupdown, settings_plugin_ifupdown, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN, + settings_plugin_interface_init)) -G_DEFINE_TYPE_EXTENDED (SCPluginIfupdown, sc_plugin_ifupdown, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, - system_config_interface_init)) +#define SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SETTINGS_TYPE_PLUGIN_IFUPDOWN, SettingsPluginIfupdownPrivate)) -#define SC_PLUGIN_IFUPDOWN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_IFUPDOWN, SCPluginIfupdownPrivate)) +static SettingsPluginIfupdown *settings_plugin_ifupdown_get (void); +NM_DEFINE_SINGLETON_GETTER (SettingsPluginIfupdown, settings_plugin_ifupdown_get, SETTINGS_TYPE_PLUGIN_IFUPDOWN); static void -sc_plugin_ifupdown_class_init (SCPluginIfupdownClass *req_class); +settings_plugin_ifupdown_class_init (SettingsPluginIfupdownClass *req_class); static void -SCPluginIfupdown_init (NMSystemConfigInterface *config); +SettingsPluginIfupdown_init (NMSettingsPlugin *config); /* Returns the plugins currently known list of connections. The returned * list is freed by the system settings service. */ static GSList* -SCPluginIfupdown_get_connections (NMSystemConfigInterface *config); +SettingsPluginIfupdown_get_connections (NMSettingsPlugin *config); /* * Return a list of device specifications which NetworkManager should not @@ -117,7 +110,7 @@ SCPluginIfupdown_get_connections (NMSystemConfigInterface *config); * each element must be allocated using g_malloc() or its variants. */ static GSList* -SCPluginIfupdown_get_unmanaged_specs (NMSystemConfigInterface *config); +SettingsPluginIfupdown_get_unmanaged_specs (NMSettingsPlugin *config); /* GObject */ @@ -132,56 +125,40 @@ GObject__set_property (GObject *object, guint prop_id, static void GObject__dispose (GObject *object); -/* other helpers */ -static const char * -get_hostname (NMSystemConfigInterface *config); - - -static void -update_system_hostname(NMInotifyHelper *inotify_helper, - struct inotify_event *evt, - const char *path, - NMSystemConfigInterface *config); - - static void -system_config_interface_init (NMSystemConfigInterface *system_config_interface_class) +settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) { - system_config_interface_class->init = SCPluginIfupdown_init; - system_config_interface_class->get_connections = SCPluginIfupdown_get_connections; - system_config_interface_class->get_unmanaged_specs = SCPluginIfupdown_get_unmanaged_specs; + plugin_iface->init = SettingsPluginIfupdown_init; + plugin_iface->get_connections = SettingsPluginIfupdown_get_connections; + plugin_iface->get_unmanaged_specs = SettingsPluginIfupdown_get_unmanaged_specs; } static void -sc_plugin_ifupdown_class_init (SCPluginIfupdownClass *req_class) +settings_plugin_ifupdown_class_init (SettingsPluginIfupdownClass *req_class) { GObjectClass *object_class = G_OBJECT_CLASS (req_class); - g_type_class_add_private (req_class, sizeof (SCPluginIfupdownPrivate)); + g_type_class_add_private (req_class, sizeof (SettingsPluginIfupdownPrivate)); object_class->dispose = GObject__dispose; object_class->get_property = GObject__get_property; object_class->set_property = GObject__set_property; g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME, - NM_SYSTEM_CONFIG_INTERFACE_NAME); - - g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, - NM_SYSTEM_CONFIG_INTERFACE_INFO); + NM_SETTINGS_PLUGIN_PROP_NAME, + NM_SETTINGS_PLUGIN_NAME); g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES, - NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES); + NM_SETTINGS_PLUGIN_PROP_INFO, + NM_SETTINGS_PLUGIN_INFO); g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME, - NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); + NM_SETTINGS_PLUGIN_PROP_CAPABILITIES, + NM_SETTINGS_PLUGIN_CAPABILITIES); } static void -bind_device_to_connection (SCPluginIfupdown *self, +bind_device_to_connection (SettingsPluginIfupdown *self, GUdevDevice *device, NMIfupdownConnection *exported) { @@ -217,13 +194,13 @@ bind_device_to_connection (SCPluginIfupdown *self, g_object_set (s_wifi, NM_SETTING_WIRELESS_MAC_ADDRESS, address, NULL); } - nm_settings_connection_commit_changes (NM_SETTINGS_CONNECTION (exported), NULL, NULL); + nm_settings_connection_commit_changes (NM_SETTINGS_CONNECTION (exported), NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, NULL, NULL); } static void -udev_device_added (SCPluginIfupdown *self, GUdevDevice *device) +udev_device_added (SettingsPluginIfupdown *self, GUdevDevice *device) { - SCPluginIfupdownPrivate *priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (self); + SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self); const char *iface, *path; NMIfupdownConnection *exported; @@ -250,13 +227,13 @@ udev_device_added (SCPluginIfupdown *self, GUdevDevice *device) bind_device_to_connection (self, device, exported); if (ALWAYS_UNMANAGE || priv->unmanage_well_known) - g_signal_emit_by_name (G_OBJECT (self), NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); + g_signal_emit_by_name (G_OBJECT (self), NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); } static void -udev_device_removed (SCPluginIfupdown *self, GUdevDevice *device) +udev_device_removed (SettingsPluginIfupdown *self, GUdevDevice *device) { - SCPluginIfupdownPrivate *priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (self); + SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self); const char *iface, *path; iface = g_udev_device_get_name (device); @@ -270,13 +247,13 @@ udev_device_removed (SCPluginIfupdown *self, GUdevDevice *device) return; if (ALWAYS_UNMANAGE || priv->unmanage_well_known) - g_signal_emit_by_name (G_OBJECT (self), NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); + g_signal_emit_by_name (G_OBJECT (self), NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); } static void -udev_device_changed (SCPluginIfupdown *self, GUdevDevice *device) +udev_device_changed (SettingsPluginIfupdown *self, GUdevDevice *device) { - SCPluginIfupdownPrivate *priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (self); + SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self); const char *iface, *path; iface = g_udev_device_get_name (device); @@ -290,7 +267,7 @@ udev_device_changed (SCPluginIfupdown *self, GUdevDevice *device) return; if (ALWAYS_UNMANAGE || priv->unmanage_well_known) - g_signal_emit_by_name (G_OBJECT (self), NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); + g_signal_emit_by_name (G_OBJECT (self), NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); } static void @@ -299,7 +276,7 @@ handle_uevent (GUdevClient *client, GUdevDevice *device, gpointer user_data) { - SCPluginIfupdown *self = SC_PLUGIN_IFUPDOWN (user_data); + SettingsPluginIfupdown *self = SETTINGS_PLUGIN_IFUPDOWN (user_data); const char *subsys; g_return_if_fail (action != NULL); @@ -318,13 +295,12 @@ handle_uevent (GUdevClient *client, } static void -SCPluginIfupdown_init (NMSystemConfigInterface *config) +SettingsPluginIfupdown_init (NMSettingsPlugin *config) { - SCPluginIfupdown *self = SC_PLUGIN_IFUPDOWN (config); - SCPluginIfupdownPrivate *priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (self); + SettingsPluginIfupdown *self = SETTINGS_PLUGIN_IFUPDOWN (config); + SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (self); GHashTable *auto_ifaces; if_block *block = NULL; - NMInotifyHelper *inotify_helper; GList *keys, *iter; GHashTableIter con_iter; const char *block_name; @@ -350,17 +326,6 @@ SCPluginIfupdown_init (NMSystemConfigInterface *config) } else g_signal_connect (priv->client, "uevent", G_CALLBACK (handle_uevent), self); - inotify_helper = nm_inotify_helper_get (); - priv->inotify_event_id = g_signal_connect (inotify_helper, - "event", - G_CALLBACK (update_system_hostname), - config); - - priv->inotify_system_hostname_wd = - nm_inotify_helper_add_watch (inotify_helper, IFUPDOWN_SYSTEM_HOSTNAME_FILE); - - update_system_hostname (inotify_helper, NULL, NULL, config); - /* Read in all the interfaces */ ifparser_init (ENI_INTERFACES_FILE, 0); block = ifparser_getfirst (); @@ -471,7 +436,7 @@ SCPluginIfupdown_init (NMSystemConfigInterface *config) for (cl_iter = con_list; cl_iter; cl_iter = g_list_next (cl_iter)) { g_signal_emit_by_name (self, - NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, + NM_SETTINGS_PLUGIN_CONNECTION_ADDED, NM_SETTINGS_CONNECTION (cl_iter->data)); } g_list_free (con_list); @@ -485,9 +450,9 @@ SCPluginIfupdown_init (NMSystemConfigInterface *config) * list is freed by the system settings service. */ static GSList* -SCPluginIfupdown_get_connections (NMSystemConfigInterface *config) +SettingsPluginIfupdown_get_connections (NMSettingsPlugin *config) { - SCPluginIfupdownPrivate *priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (config); + SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (config); GSList *connections; nm_log_info (LOGD_SETTINGS, "(%d) ... get_connections.", GPOINTER_TO_UINT(config)); @@ -509,9 +474,9 @@ SCPluginIfupdown_get_connections (NMSystemConfigInterface *config) * each element must be allocated using g_malloc() or its variants. */ static GSList* -SCPluginIfupdown_get_unmanaged_specs (NMSystemConfigInterface *config) +SettingsPluginIfupdown_get_unmanaged_specs (NMSettingsPlugin *config) { - SCPluginIfupdownPrivate *priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (config); + SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (config); GSList *specs = NULL; GHashTableIter iter; GUdevDevice *device; @@ -536,78 +501,8 @@ SCPluginIfupdown_get_unmanaged_specs (NMSystemConfigInterface *config) return specs; } - -static const char * -get_hostname (NMSystemConfigInterface *config) -{ - SCPluginIfupdownPrivate *priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (config); - return priv->hostname; -} - static void -update_system_hostname(NMInotifyHelper *inotify_helper, - struct inotify_event *evt, - const char *path, - NMSystemConfigInterface *config) -{ - SCPluginIfupdownPrivate *priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (config); - gchar *hostname_file = NULL; - gsize hostname_file_len = 0; - GError *error = NULL; - - nm_log_info (LOGD_SETTINGS, "update_system_hostname"); - - if (evt && evt->wd != priv->inotify_system_hostname_wd) - return; - - if(!g_file_get_contents ( IFUPDOWN_SYSTEM_HOSTNAME_FILE, - &hostname_file, - &hostname_file_len, - &error)) { - nm_log_warn (LOGD_SETTINGS, "update_system_hostname() - couldn't read " - IFUPDOWN_SYSTEM_HOSTNAME_FILE " (%d/%s)", - error->code, error->message); - return; - } - - g_free(priv->hostname); - priv->hostname = g_strstrip(hostname_file); - - /* We shouldn't return a zero-length hostname, but NULL */ - if (priv->hostname && !strlen (priv->hostname)) { - g_free (priv->hostname); - priv->hostname = NULL; - } - - g_object_notify (G_OBJECT (config), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); -} - -static void -write_system_hostname(NMSystemConfigInterface *config, - const char *newhostname) -{ - GError *error = NULL; - SCPluginIfupdownPrivate *priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (config); - nm_log_info (LOGD_SETTINGS, "write_system_hostname: %s", newhostname); - - g_return_if_fail (newhostname); - - if(!g_file_set_contents ( IFUPDOWN_SYSTEM_HOSTNAME_FILE, - newhostname, - -1, - &error)) { - nm_log_warn (LOGD_SETTINGS, "update_system_hostname() - couldn't write hostname (%s) to " - IFUPDOWN_SYSTEM_HOSTNAME_FILE " (%d/%s)", - newhostname, error->code, error->message); - } else { - priv->hostname = g_strdup (newhostname); - } - g_object_notify (G_OBJECT (config), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); -} - - -static void -sc_plugin_ifupdown_init (SCPluginIfupdown *plugin) +settings_plugin_ifupdown_init (SettingsPluginIfupdown *plugin) { } @@ -615,23 +510,16 @@ static void GObject__get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMSystemConfigInterface *self = NM_SYSTEM_CONFIG_INTERFACE (object); - switch (prop_id) { - case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME: + case NM_SETTINGS_PLUGIN_PROP_NAME: g_value_set_string (value, IFUPDOWN_PLUGIN_NAME); break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO: + case NM_SETTINGS_PLUGIN_PROP_INFO: g_value_set_string (value, IFUPDOWN_PLUGIN_INFO); break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES: - g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME); + case NM_SETTINGS_PLUGIN_PROP_CAPABILITIES: + g_value_set_uint (value, NM_SETTINGS_PLUGIN_CAP_NONE); break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME: - { - g_value_set_string (value, get_hostname(self)); - break; - } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -643,15 +531,6 @@ GObject__set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { - case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME: - { - const gchar *hostname = g_value_get_string (value); - if (hostname && strlen (hostname) < 1) - hostname = NULL; - write_system_hostname(NM_SYSTEM_CONFIG_INTERFACE(object), - hostname); - break; - } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -661,14 +540,8 @@ GObject__set_property (GObject *object, guint prop_id, static void GObject__dispose (GObject *object) { - SCPluginIfupdown *plugin = SC_PLUGIN_IFUPDOWN (object); - SCPluginIfupdownPrivate *priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (plugin); - NMInotifyHelper *inotify_helper = nm_inotify_helper_get (); - - g_signal_handler_disconnect (inotify_helper, priv->inotify_event_id); - - if (priv->inotify_system_hostname_wd >= 0) - nm_inotify_helper_remove_watch (inotify_helper, priv->inotify_system_hostname_wd); + SettingsPluginIfupdown *plugin = SETTINGS_PLUGIN_IFUPDOWN (object); + SettingsPluginIfupdownPrivate *priv = SETTINGS_PLUGIN_IFUPDOWN_GET_PRIVATE (plugin); if (priv->kernel_ifaces) g_hash_table_destroy(priv->kernel_ifaces); @@ -680,21 +553,12 @@ GObject__dispose (GObject *object) g_object_unref (priv->client); - G_OBJECT_CLASS (sc_plugin_ifupdown_parent_class)->dispose (object); + G_OBJECT_CLASS (settings_plugin_ifupdown_parent_class)->dispose (object); } G_MODULE_EXPORT GObject * -nm_system_config_factory (void) +nm_settings_plugin_factory (void) { - static SCPluginIfupdown *singleton = NULL; - SCPluginIfupdownPrivate *priv; - - if (!singleton) { - singleton = SC_PLUGIN_IFUPDOWN (g_object_new (SC_TYPE_PLUGIN_IFUPDOWN, NULL)); - priv = SC_PLUGIN_IFUPDOWN_GET_PRIVATE (singleton); - } else - g_object_ref (singleton); - - return G_OBJECT (singleton); + return g_object_ref (settings_plugin_ifupdown_get ()); } diff --git a/src/settings/plugins/ifupdown/plugin.h b/src/settings/plugins/ifupdown/plugin.h index 943b8b9f..090178f2 100644 --- a/src/settings/plugins/ifupdown/plugin.h +++ b/src/settings/plugins/ifupdown/plugin.h @@ -24,28 +24,28 @@ #ifndef _PLUGIN_H_ #define _PLUGIN_H_ -#include +#include "nm-default.h" #define PLUGIN_NAME "ifupdown" -#define SC_TYPE_PLUGIN_IFUPDOWN (sc_plugin_ifupdown_get_type ()) -#define SC_PLUGIN_IFUPDOWN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_IFUPDOWN, SCPluginIfupdown)) -#define SC_PLUGIN_IFUPDOWN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_IFUPDOWN, SCPluginIfupdownClass)) -#define SC_IS_PLUGIN_IFUPDOWN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_IFUPDOWN)) -#define SC_IS_PLUGIN_IFUPDOWN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_PLUGIN_IFUPDOWN)) -#define SC_PLUGIN_IFUPDOWN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_IFUPDOWN, SCPluginIfupdownClass)) +#define SETTINGS_TYPE_PLUGIN_IFUPDOWN (settings_plugin_ifupdown_get_type ()) +#define SETTINGS_PLUGIN_IFUPDOWN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SETTINGS_TYPE_PLUGIN_IFUPDOWN, SettingsPluginIfupdown)) +#define SETTINGS_PLUGIN_IFUPDOWN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SETTINGS_TYPE_PLUGIN_IFUPDOWN, SettingsPluginIfupdownClass)) +#define SETTINGS_IS_PLUGIN_IFUPDOWN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SETTINGS_TYPE_PLUGIN_IFUPDOWN)) +#define SETTINGS_IS_PLUGIN_IFUPDOWN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SETTINGS_TYPE_PLUGIN_IFUPDOWN)) +#define SETTINGS_PLUGIN_IFUPDOWN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SETTINGS_TYPE_PLUGIN_IFUPDOWN, SettingsPluginIfupdownClass)) -typedef struct _SCPluginIfupdown SCPluginIfupdown; -typedef struct _SCPluginIfupdownClass SCPluginIfupdownClass; +typedef struct _SettingsPluginIfupdown SettingsPluginIfupdown; +typedef struct _SettingsPluginIfupdownClass SettingsPluginIfupdownClass; -struct _SCPluginIfupdown { +struct _SettingsPluginIfupdown { GObject parent; }; -struct _SCPluginIfupdownClass { +struct _SettingsPluginIfupdownClass { GObjectClass parent; }; -GType sc_plugin_ifupdown_get_type (void); +GType settings_plugin_ifupdown_get_type (void); #endif /* _PLUGIN_H_ */ diff --git a/src/settings/plugins/ifupdown/tests/Makefile.am b/src/settings/plugins/ifupdown/tests/Makefile.am index 4ae44a0b..29e9a7ed 100644 --- a/src/settings/plugins/ifupdown/tests/Makefile.am +++ b/src/settings/plugins/ifupdown/tests/Makefile.am @@ -1,15 +1,15 @@ if ENABLE_TESTS AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/settings \ -I$(srcdir)/../ \ -DG_LOG_DOMAIN=\""NetworkManager-ifupdown"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ -DTEST_ENI_DIR=\"$(abs_srcdir)\" diff --git a/src/settings/plugins/ifupdown/tests/Makefile.in b/src/settings/plugins/ifupdown/tests/Makefile.in index 2387a257..8ad1c0ab 100644 --- a/src/settings/plugins/ifupdown/tests/Makefile.in +++ b/src/settings/plugins/ifupdown/tests/Makefile.in @@ -406,7 +406,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -418,8 +417,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -429,6 +426,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -483,16 +481,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -529,6 +524,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -557,7 +554,6 @@ 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@ @@ -572,6 +568,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -632,6 +630,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -639,6 +638,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -655,15 +655,15 @@ with_netconfig = @with_netconfig@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ @ENABLE_TESTS_TRUE@AM_CPPFLAGS = \ -@ENABLE_TESTS_TRUE@ -I$(top_srcdir)/include \ -@ENABLE_TESTS_TRUE@ -I$(top_builddir)/include \ +@ENABLE_TESTS_TRUE@ -I$(top_srcdir)/shared \ +@ENABLE_TESTS_TRUE@ -I$(top_builddir)/shared \ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/libnm-core \ @ENABLE_TESTS_TRUE@ -I$(top_builddir)/libnm-core \ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/src \ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/src/settings \ @ENABLE_TESTS_TRUE@ -I$(srcdir)/../ \ @ENABLE_TESTS_TRUE@ -DG_LOG_DOMAIN=\""NetworkManager-ifupdown"\" \ -@ENABLE_TESTS_TRUE@ -DNETWORKMANAGER_COMPILATION \ +@ENABLE_TESTS_TRUE@ -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ @ENABLE_TESTS_TRUE@ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ @ENABLE_TESTS_TRUE@ $(GLIB_CFLAGS) \ @ENABLE_TESTS_TRUE@ -DTEST_ENI_DIR=\"$(abs_srcdir)\" diff --git a/src/settings/plugins/ifupdown/tests/test-ifupdown.c b/src/settings/plugins/ifupdown/tests/test-ifupdown.c index 1c100ac2..24e8afdc 100644 --- a/src/settings/plugins/ifupdown/tests/test-ifupdown.c +++ b/src/settings/plugins/ifupdown/tests/test-ifupdown.c @@ -20,11 +20,10 @@ #include "config.h" -#include #include +#include "nm-default.h" #include "nm-core-internal.h" -#include "nm-logging.h" #include "interface_parser.h" #include "parser.h" @@ -844,16 +843,12 @@ test20_source_stanza (const char *path) expected_free (e); } +NMTST_DEFINE (); + int main (int argc, char **argv) { -#if !GLIB_CHECK_VERSION (2, 35, 0) - g_type_init (); -#endif - - nm_logging_setup ("WARN", "DEFAULT", NULL, NULL); - - g_test_init (&argc, &argv, NULL); + nmtst_init_assert_logging (&argc, &argv, "WARN", "DEFAULT"); if (0) dump_blocks (); diff --git a/src/settings/plugins/keyfile/Makefile.am b/src/settings/plugins/keyfile/Makefile.am index 919b0805..ddcd15b2 100644 --- a/src/settings/plugins/keyfile/Makefile.am +++ b/src/settings/plugins/keyfile/Makefile.am @@ -5,15 +5,14 @@ SUBDIRS = . tests AM_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/settings \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-keyfile"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) \ -DNMCONFDIR=\"$(nmconfdir)\" noinst_LTLIBRARIES = \ @@ -28,8 +27,7 @@ libkeyfile_io_la_SOURCES = \ writer.c \ writer.h \ utils.c \ - utils.h \ - common.h + utils.h libkeyfile_io_la_LIBADD = $(GLIB_LIBS) diff --git a/src/settings/plugins/keyfile/Makefile.in b/src/settings/plugins/keyfile/Makefile.in index 1514768b..9c078ca4 100644 --- a/src/settings/plugins/keyfile/Makefile.in +++ b/src/settings/plugins/keyfile/Makefile.in @@ -246,7 +246,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -258,8 +257,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -269,6 +266,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -323,16 +321,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -369,6 +364,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -397,7 +394,6 @@ 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@ @@ -412,6 +408,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -472,6 +470,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -479,6 +478,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -498,15 +498,14 @@ SUBDIRS = . tests AM_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/settings \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -DG_LOG_DOMAIN=\""NetworkManager-keyfile"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) \ -DNMCONFDIR=\"$(nmconfdir)\" noinst_LTLIBRARIES = \ @@ -521,8 +520,7 @@ libkeyfile_io_la_SOURCES = \ writer.c \ writer.h \ utils.c \ - utils.h \ - common.h + utils.h libkeyfile_io_la_LIBADD = $(GLIB_LIBS) diff --git a/src/settings/plugins/keyfile/common.h b/src/settings/plugins/keyfile/common.h deleted file mode 100644 index 86fe0028..00000000 --- a/src/settings/plugins/keyfile/common.h +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager system settings service - * - * 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. - * - * (C) Copyright 2008 - 2013 Red Hat, Inc. - */ - -#ifndef __COMMON_H__ -#define __COMMON_H__ - -#include - -#define KEYFILE_PLUGIN_NAME "keyfile" -#define KEYFILE_PLUGIN_INFO "(c) 2007 - 2015 Red Hat, Inc. To report bugs please use the NetworkManager mailing list." - -#define KEYFILE_DIR NMCONFDIR "/system-connections" - -#endif /* __COMMON_H__ */ - diff --git a/src/settings/plugins/keyfile/nm-keyfile-connection.c b/src/settings/plugins/keyfile/nm-keyfile-connection.c index 8fb94302..c217de68 100644 --- a/src/settings/plugins/keyfile/nm-keyfile-connection.c +++ b/src/settings/plugins/keyfile/nm-keyfile-connection.c @@ -27,12 +27,13 @@ #include #include -#include "nm-system-config-interface.h" -#include "nm-dbus-glib-types.h" +#include "nm-default.h" +#include "nm-settings-plugin.h" #include "nm-keyfile-connection.h" #include "reader.h" #include "writer.h" -#include "common.h" +#include "utils.h" +#include "nm-logging.h" G_DEFINE_TYPE (NMKeyfileConnection, nm_keyfile_connection, NM_TYPE_SETTINGS_CONNECTION) @@ -88,6 +89,7 @@ nm_keyfile_connection_new (NMConnection *source, static void commit_changes (NMSettingsConnection *connection, + NMSettingsConnectionCommitReason commit_reason, NMSettingsConnectionCommitFunc callback, gpointer user_data) { @@ -96,6 +98,8 @@ commit_changes (NMSettingsConnection *connection, if (!nm_keyfile_plugin_write_connection (NM_CONNECTION (connection), nm_settings_connection_get_filename (connection), + NM_FLAGS_ALL (commit_reason, NM_SETTINGS_CONNECTION_COMMIT_REASON_USER_ACTION + | NM_SETTINGS_CONNECTION_COMMIT_REASON_ID_CHANGED), &path, &error)) { callback (connection, error, user_data); @@ -104,10 +108,28 @@ commit_changes (NMSettingsConnection *connection, } /* Update the filename if it changed */ - if (path) + if ( path + && g_strcmp0 (path, nm_settings_connection_get_filename (connection)) != 0) { + gs_free char *old_path = g_strdup (nm_settings_connection_get_filename (connection)); + nm_settings_connection_set_filename (connection, path); + if (old_path) { + nm_log_info (LOGD_SETTINGS, "keyfile: update "NM_KEYFILE_CONNECTION_LOG_FMT" and rename from \"%s\"", + NM_KEYFILE_CONNECTION_LOG_ARG (connection), + old_path); + } else { + nm_log_info (LOGD_SETTINGS, "keyfile: update "NM_KEYFILE_CONNECTION_LOG_FMT" and persist connection", + NM_KEYFILE_CONNECTION_LOG_ARG (connection)); + } + } else { + nm_log_info (LOGD_SETTINGS, "keyfile: update "NM_KEYFILE_CONNECTION_LOG_FMT, + NM_KEYFILE_CONNECTION_LOG_ARG (connection)); + } + + g_free (path); NM_SETTINGS_CONNECTION_CLASS (nm_keyfile_connection_parent_class)->commit_changes (connection, + commit_reason, callback, user_data); } diff --git a/src/settings/plugins/keyfile/plugin.c b/src/settings/plugins/keyfile/plugin.c index 7f21e71e..e352e523 100644 --- a/src/settings/plugins/keyfile/plugin.c +++ b/src/settings/plugins/keyfile/plugin.c @@ -27,62 +27,51 @@ #include #include -#include #include -#include #include #include #include #include -#include -#include +#include "nm-config.h" +#include "nm-default.h" #include "nm-core-internal.h" #include "plugin.h" -#include "nm-system-config-interface.h" +#include "nm-settings-plugin.h" #include "nm-keyfile-connection.h" #include "writer.h" -#include "common.h" #include "utils.h" -#include "gsystem-local-alloc.h" -static char *plugin_get_hostname (SCPluginKeyfile *plugin); -static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class); +static void settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface); -G_DEFINE_TYPE_EXTENDED (SCPluginKeyfile, sc_plugin_keyfile, G_TYPE_OBJECT, 0, - G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, - system_config_interface_init)) +G_DEFINE_TYPE_EXTENDED (SettingsPluginKeyfile, settings_plugin_keyfile, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_SETTINGS_PLUGIN, + settings_plugin_interface_init)) -#define SC_PLUGIN_KEYFILE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_KEYFILE, SCPluginKeyfilePrivate)) +#define SETTINGS_PLUGIN_KEYFILE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SETTINGS_TYPE_PLUGIN_KEYFILE, SettingsPluginKeyfilePrivate)) typedef struct { GHashTable *connections; /* uuid::connection */ gboolean initialized; GFileMonitor *monitor; - guint monitor_id; + gulong monitor_id; - const char *conf_file; - GFileMonitor *conf_file_monitor; - guint conf_file_monitor_id; - - char *hostname; - - gboolean disposed; -} SCPluginKeyfilePrivate; + NMConfig *config; +} SettingsPluginKeyfilePrivate; static void connection_removed_cb (NMSettingsConnection *obj, gpointer user_data) { - g_hash_table_remove (SC_PLUGIN_KEYFILE_GET_PRIVATE (user_data)->connections, + g_hash_table_remove (SETTINGS_PLUGIN_KEYFILE_GET_PRIVATE (user_data)->connections, nm_connection_get_uuid (NM_CONNECTION (obj))); } /* Monitoring */ static void -remove_connection (SCPluginKeyfile *self, NMKeyfileConnection *connection) +remove_connection (SettingsPluginKeyfile *self, NMKeyfileConnection *connection) { gboolean removed; @@ -93,7 +82,7 @@ remove_connection (SCPluginKeyfile *self, NMKeyfileConnection *connection) /* Removing from the hash table should drop the last reference */ g_object_ref (connection); g_signal_handlers_disconnect_by_func (connection, connection_removed_cb, self); - removed = g_hash_table_remove (SC_PLUGIN_KEYFILE_GET_PRIVATE (self)->connections, + removed = g_hash_table_remove (SETTINGS_PLUGIN_KEYFILE_GET_PRIVATE (self)->connections, nm_connection_get_uuid (NM_CONNECTION (connection))); nm_settings_connection_signal_remove (NM_SETTINGS_CONNECTION (connection)); g_object_unref (connection); @@ -102,9 +91,9 @@ remove_connection (SCPluginKeyfile *self, NMKeyfileConnection *connection) } static NMKeyfileConnection * -find_by_path (SCPluginKeyfile *self, const char *path) +find_by_path (SettingsPluginKeyfile *self, const char *path) { - SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self); + SettingsPluginKeyfilePrivate *priv = SETTINGS_PLUGIN_KEYFILE_GET_PRIVATE (self); GHashTableIter iter; NMSettingsConnection *candidate = NULL; @@ -150,7 +139,7 @@ find_by_path (SCPluginKeyfile *self, const char *path) * Returns: the updated connection. * */ static NMKeyfileConnection * -update_connection (SCPluginKeyfile *self, +update_connection (SettingsPluginKeyfile *self, NMConnection *source, const char *full_path, NMKeyfileConnection *connection, @@ -158,7 +147,7 @@ update_connection (SCPluginKeyfile *self, GHashTable *protected_connections, GError **error) { - SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self); + SettingsPluginKeyfilePrivate *priv = SETTINGS_PLUGIN_KEYFILE_GET_PRIVATE (self); NMKeyfileConnection *connection_new; NMKeyfileConnection *connection_by_uuid; GError *local = NULL; @@ -274,7 +263,7 @@ update_connection (SCPluginKeyfile *self, if (!source) { /* Only raise the signal if we were called without source, i.e. if we read the connection from file. * Otherwise, we were called by add_connection() which does not expect the signal. */ - g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, connection_new); + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_CONNECTION_ADDED, connection_new); } return connection_new; } @@ -287,8 +276,8 @@ dir_changed (GFileMonitor *monitor, GFileMonitorEvent event_type, gpointer user_data) { - NMSystemConfigInterface *config = NM_SYSTEM_CONFIG_INTERFACE (user_data); - SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config); + NMSettingsPlugin *config = NM_SETTINGS_PLUGIN (user_data); + SettingsPluginKeyfile *self = SETTINGS_PLUGIN_KEYFILE (config); NMKeyfileConnection *connection; char *full_path; gboolean exists; @@ -307,12 +296,12 @@ dir_changed (GFileMonitor *monitor, switch (event_type) { case G_FILE_MONITOR_EVENT_DELETED: if (!exists && connection) - remove_connection (SC_PLUGIN_KEYFILE (config), connection); + remove_connection (SETTINGS_PLUGIN_KEYFILE (config), connection); break; case G_FILE_MONITOR_EVENT_CREATED: case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: if (exists) - update_connection (SC_PLUGIN_KEYFILE (config), NULL, full_path, connection, TRUE, NULL, NULL); + update_connection (SETTINGS_PLUGIN_KEYFILE (config), NULL, full_path, connection, TRUE, NULL, NULL); break; default: break; @@ -322,51 +311,30 @@ dir_changed (GFileMonitor *monitor, } static void -conf_file_changed (GFileMonitor *monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer data) +config_changed_cb (NMConfig *config, + NMConfigData *config_data, + NMConfigChangeFlags changes, + NMConfigData *old_data, + SettingsPluginKeyfile *self) { - SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (data); - SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self); - char *tmp; - - switch (event_type) { - case G_FILE_MONITOR_EVENT_DELETED: - case G_FILE_MONITOR_EVENT_CREATED: - case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: - g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); - - /* hostname */ - tmp = plugin_get_hostname (self); - if ((tmp && !priv->hostname) - || (!tmp && priv->hostname) - || (priv->hostname && tmp && strcmp (priv->hostname, tmp))) { - - g_free (priv->hostname); - priv->hostname = tmp; - tmp = NULL; - g_object_notify (G_OBJECT (self), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); - } + gs_free char *old_value = NULL, *new_value = NULL; - g_free (tmp); + old_value = nm_config_data_get_value (old_data, NM_CONFIG_KEYFILE_GROUP_KEYFILE, NM_CONFIG_KEYFILE_KEY_KEYFILE_UNMANAGED_DEVICES, NM_CONFIG_GET_VALUE_TYPE_SPEC); + new_value = nm_config_data_get_value (config_data, NM_CONFIG_KEYFILE_GROUP_KEYFILE, NM_CONFIG_KEYFILE_KEY_KEYFILE_UNMANAGED_DEVICES, NM_CONFIG_GET_VALUE_TYPE_SPEC); - break; - default: - break; - } + if (g_strcmp0 (old_value, new_value) != 0) + g_signal_emit_by_name (self, NM_SETTINGS_PLUGIN_UNMANAGED_SPECS_CHANGED); } static void -setup_monitoring (NMSystemConfigInterface *config) +setup_monitoring (NMSettingsPlugin *config) { - SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config); + SettingsPluginKeyfilePrivate *priv = SETTINGS_PLUGIN_KEYFILE_GET_PRIVATE (config); GFile *file; GFileMonitor *monitor; if (nm_config_get_monitor_connection_files (nm_config_get ())) { - file = g_file_new_for_path (KEYFILE_DIR); + file = g_file_new_for_path (nm_keyfile_plugin_get_path ()); monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); g_object_unref (file); @@ -376,16 +344,10 @@ setup_monitoring (NMSystemConfigInterface *config) } } - if (priv->conf_file) { - file = g_file_new_for_path (priv->conf_file); - monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, NULL); - g_object_unref (file); - - if (monitor) { - priv->conf_file_monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (conf_file_changed), config); - priv->conf_file_monitor = monitor; - } - } + g_signal_connect (G_OBJECT (priv->config), + NM_CONFIG_SIGNAL_CONFIG_CHANGED, + G_CALLBACK (config_changed_cb), + config); } static GHashTable * @@ -426,10 +388,10 @@ _sort_paths (const char **f1, const char **f2, GHashTable *paths) } static void -read_connections (NMSystemConfigInterface *config) +read_connections (NMSettingsPlugin *config) { - SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config); - SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self); + SettingsPluginKeyfile *self = SETTINGS_PLUGIN_KEYFILE (config); + SettingsPluginKeyfilePrivate *priv = SETTINGS_PLUGIN_KEYFILE_GET_PRIVATE (self); GDir *dir; GError *error = NULL; const char *item; @@ -441,10 +403,10 @@ read_connections (NMSystemConfigInterface *config) GPtrArray *filenames; GHashTable *paths; - dir = g_dir_open (KEYFILE_DIR, 0, &error); + dir = g_dir_open (nm_keyfile_plugin_get_path (), 0, &error); if (!dir) { nm_log_warn (LOGD_SETTINGS, "keyfile: cannot read directory '%s': (%d) %s", - KEYFILE_DIR, + nm_keyfile_plugin_get_path (), error ? error->code : -1, error && error->message ? error->message : "(unknown)"); g_clear_error (&error); @@ -457,7 +419,7 @@ read_connections (NMSystemConfigInterface *config) while ((item = g_dir_read_name (dir))) { if (nm_keyfile_plugin_utils_should_ignore_file (item)) continue; - g_ptr_array_add (filenames, g_build_filename (KEYFILE_DIR, item, NULL)); + g_ptr_array_add (filenames, g_build_filename (nm_keyfile_plugin_get_path (), item, NULL)); } g_dir_close (dir); @@ -499,9 +461,9 @@ read_connections (NMSystemConfigInterface *config) /* Plugin */ static GSList * -get_connections (NMSystemConfigInterface *config) +get_connections (NMSettingsPlugin *config) { - SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config); + SettingsPluginKeyfilePrivate *priv = SETTINGS_PLUGIN_KEYFILE_GET_PRIVATE (config); if (!priv->initialized) { setup_monitoring (config); @@ -512,14 +474,14 @@ get_connections (NMSystemConfigInterface *config) } static gboolean -load_connection (NMSystemConfigInterface *config, +load_connection (NMSettingsPlugin *config, const char *filename) { - SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config); + SettingsPluginKeyfile *self = SETTINGS_PLUGIN_KEYFILE (config); NMKeyfileConnection *connection; - int dir_len = strlen (KEYFILE_DIR); + int dir_len = strlen (nm_keyfile_plugin_get_path ()); - if ( strncmp (filename, KEYFILE_DIR, dir_len) != 0 + if ( strncmp (filename, nm_keyfile_plugin_get_path (), dir_len) != 0 || filename[dir_len] != '/' || strchr (filename + dir_len + 1, '/') != NULL) return FALSE; @@ -533,157 +495,46 @@ load_connection (NMSystemConfigInterface *config, } static void -reload_connections (NMSystemConfigInterface *config) +reload_connections (NMSettingsPlugin *config) { read_connections (config); } static NMSettingsConnection * -add_connection (NMSystemConfigInterface *config, +add_connection (NMSettingsPlugin *config, NMConnection *connection, gboolean save_to_disk, GError **error) { - SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config); + SettingsPluginKeyfile *self = SETTINGS_PLUGIN_KEYFILE (config); gs_free char *path = NULL; if (save_to_disk) { - if (!nm_keyfile_plugin_write_connection (connection, NULL, &path, error)) + if (!nm_keyfile_plugin_write_connection (connection, NULL, FALSE, &path, error)) return NULL; } return NM_SETTINGS_CONNECTION (update_connection (self, connection, path, NULL, FALSE, NULL, error)); } -static gboolean -parse_key_file_allow_none (SCPluginKeyfilePrivate *priv, - GKeyFile *key_file, - GError **error) -{ - gboolean ret = FALSE; - GError *local_error = NULL; - - if (!g_key_file_load_from_file (key_file, priv->conf_file, G_KEY_FILE_NONE, &local_error)) { - if (g_error_matches (local_error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) - g_clear_error (&local_error); - else { - g_propagate_prefixed_error (error, local_error, - "Error parsing file '%s': ", - priv->conf_file); - goto out; - } - } - ret = TRUE; - - out: - return ret; -} - static GSList * -get_unmanaged_specs (NMSystemConfigInterface *config) -{ - SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (config); - GKeyFile *key_file; - GSList *specs = NULL; - GError *error = NULL; - - if (!priv->conf_file) - return NULL; - - key_file = nm_config_create_keyfile (); - if (parse_key_file_allow_none (priv, key_file, &error)) - specs = nm_config_get_device_match_spec (key_file, NM_CONFIG_KEYFILE_GROUP_KEYFILE, "unmanaged-devices", NULL); - - if (error) { - nm_log_warn (LOGD_SETTINGS, "keyfile: error getting unmanaged specs: %s", error->message); - g_error_free (error); - } - g_key_file_free (key_file); - - return specs; -} - -static char * -plugin_get_hostname (SCPluginKeyfile *plugin) -{ - SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (plugin); - GKeyFile *key_file; - char *hostname = NULL; - GError *error = NULL; - - if (!priv->conf_file) - return NULL; - - key_file = g_key_file_new (); - if (!parse_key_file_allow_none (priv, key_file, &error)) - goto out; - - hostname = g_key_file_get_value (key_file, NM_CONFIG_KEYFILE_GROUP_KEYFILE, "hostname", NULL); - - out: - if (error) { - nm_log_warn (LOGD_SETTINGS, "keyfile: error getting hostname: %s", error->message); - g_error_free (error); - } - if (key_file) - g_key_file_free (key_file); - - return hostname; -} - -static gboolean -plugin_set_hostname (SCPluginKeyfile *plugin, const char *hostname) +get_unmanaged_specs (NMSettingsPlugin *config) { - gboolean ret = FALSE; - SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (plugin); - GKeyFile *key_file = NULL; - GError *error = NULL; - char *data = NULL; - gsize len; - - if (!priv->conf_file) { - g_set_error (&error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Error saving hostname: no config file"); - goto out; - } - - g_free (priv->hostname); - priv->hostname = g_strdup (hostname); - - key_file = g_key_file_new (); - if (!parse_key_file_allow_none (priv, key_file, &error)) - goto out; - - g_key_file_set_string (key_file, NM_CONFIG_KEYFILE_GROUP_KEYFILE, "hostname", hostname); - - data = g_key_file_to_data (key_file, &len, &error); - if (!data) - goto out; - - if (!g_file_set_contents (priv->conf_file, data, len, &error)) { - g_prefix_error (&error, "Error saving hostname: "); - goto out; - } - - ret = TRUE; - - out: - if (error) { - nm_log_warn (LOGD_SETTINGS, "keyfile: error setting hostname: %s", error->message); - g_error_free (error); - } - g_free (data); - if (key_file) - g_key_file_free (key_file); - - return ret; + SettingsPluginKeyfilePrivate *priv = SETTINGS_PLUGIN_KEYFILE_GET_PRIVATE (config); + gs_free char *value = NULL; + + value = nm_config_data_get_value (nm_config_get_data (priv->config), + NM_CONFIG_KEYFILE_GROUP_KEYFILE, + NM_CONFIG_KEYFILE_KEY_KEYFILE_UNMANAGED_DEVICES, + NM_CONFIG_GET_VALUE_TYPE_SPEC); + return nm_match_spec_split (value); } /* GObject */ static void -sc_plugin_keyfile_init (SCPluginKeyfile *plugin) +settings_plugin_keyfile_init (SettingsPluginKeyfile *plugin) { - SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (plugin); + SettingsPluginKeyfilePrivate *priv = SETTINGS_PLUGIN_KEYFILE_GET_PRIVATE (plugin); priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); } @@ -693,18 +544,14 @@ get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { - case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME: + case NM_SETTINGS_PLUGIN_PROP_NAME: g_value_set_string (value, KEYFILE_PLUGIN_NAME); break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO: + case NM_SETTINGS_PLUGIN_PROP_INFO: g_value_set_string (value, KEYFILE_PLUGIN_INFO); break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES: - g_value_set_uint (value, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_CONNECTIONS | - NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME); - break; - case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME: - g_value_set_string (value, SC_PLUGIN_KEYFILE_GET_PRIVATE (object)->hostname); + case NM_SETTINGS_PLUGIN_PROP_CAPABILITIES: + g_value_set_uint (value, NM_SETTINGS_PLUGIN_CAP_MODIFY_CONNECTIONS); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -716,15 +563,7 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - const char *hostname; - switch (prop_id) { - case NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME: - hostname = g_value_get_string (value); - if (hostname && strlen (hostname) < 1) - hostname = NULL; - plugin_set_hostname (SC_PLUGIN_KEYFILE (object), hostname); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -732,97 +571,81 @@ set_property (GObject *object, guint prop_id, } static void -dispose (GObject *object) +constructed (GObject *object) { - SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (object); - - if (priv->disposed) - goto out; + SettingsPluginKeyfilePrivate *priv = SETTINGS_PLUGIN_KEYFILE_GET_PRIVATE (object); + + priv->config = g_object_ref (nm_config_get ()); + if (nm_config_data_has_value (nm_config_get_data_orig (priv->config), + NM_CONFIG_KEYFILE_GROUP_KEYFILE, + NM_CONFIG_KEYFILE_KEY_KEYFILE_HOSTNAME, + NM_CONFIG_GET_VALUE_RAW)) + nm_log_warn (LOGD_SETTINGS, "keyfile: 'hostname' option is deprecated and has no effect"); +} - priv->disposed = TRUE; +static void +dispose (GObject *object) +{ + SettingsPluginKeyfilePrivate *priv = SETTINGS_PLUGIN_KEYFILE_GET_PRIVATE (object); if (priv->monitor) { - if (priv->monitor_id) - g_signal_handler_disconnect (priv->monitor, priv->monitor_id); + nm_clear_g_signal_handler (priv->monitor, &priv->monitor_id); g_file_monitor_cancel (priv->monitor); - g_object_unref (priv->monitor); - } - - if (priv->conf_file_monitor) { - if (priv->conf_file_monitor_id) - g_signal_handler_disconnect (priv->conf_file_monitor, priv->conf_file_monitor_id); - - g_file_monitor_cancel (priv->conf_file_monitor); - g_object_unref (priv->conf_file_monitor); + g_clear_object (&priv->monitor); } - g_free (priv->hostname); - if (priv->connections) { g_hash_table_destroy (priv->connections); priv->connections = NULL; } -out: - G_OBJECT_CLASS (sc_plugin_keyfile_parent_class)->dispose (object); + if (priv->config) { + g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, object); + g_clear_object (&priv->config); + } + + G_OBJECT_CLASS (settings_plugin_keyfile_parent_class)->dispose (object); } static void -sc_plugin_keyfile_class_init (SCPluginKeyfileClass *req_class) +settings_plugin_keyfile_class_init (SettingsPluginKeyfileClass *req_class) { GObjectClass *object_class = G_OBJECT_CLASS (req_class); - g_type_class_add_private (req_class, sizeof (SCPluginKeyfilePrivate)); + g_type_class_add_private (req_class, sizeof (SettingsPluginKeyfilePrivate)); + object_class->constructed = constructed; object_class->dispose = dispose; object_class->get_property = get_property; object_class->set_property = set_property; g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME, - NM_SYSTEM_CONFIG_INTERFACE_NAME); - - g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, - NM_SYSTEM_CONFIG_INTERFACE_INFO); + NM_SETTINGS_PLUGIN_PROP_NAME, + NM_SETTINGS_PLUGIN_NAME); g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES, - NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES); + NM_SETTINGS_PLUGIN_PROP_INFO, + NM_SETTINGS_PLUGIN_INFO); g_object_class_override_property (object_class, - NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME, - NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); + NM_SETTINGS_PLUGIN_PROP_CAPABILITIES, + NM_SETTINGS_PLUGIN_CAPABILITIES); } static void -system_config_interface_init (NMSystemConfigInterface *system_config_interface_class) +settings_plugin_interface_init (NMSettingsPluginInterface *plugin_iface) { /* interface implementation */ - system_config_interface_class->get_connections = get_connections; - system_config_interface_class->load_connection = load_connection; - system_config_interface_class->reload_connections = reload_connections; - system_config_interface_class->add_connection = add_connection; - system_config_interface_class->get_unmanaged_specs = get_unmanaged_specs; + plugin_iface->get_connections = get_connections; + plugin_iface->load_connection = load_connection; + plugin_iface->reload_connections = reload_connections; + plugin_iface->add_connection = add_connection; + plugin_iface->get_unmanaged_specs = get_unmanaged_specs; } GObject * nm_settings_keyfile_plugin_new (void) { - static SCPluginKeyfile *singleton = NULL; - SCPluginKeyfilePrivate *priv; - - if (!singleton) { - singleton = SC_PLUGIN_KEYFILE (g_object_new (SC_TYPE_PLUGIN_KEYFILE, NULL)); - priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (singleton); - - priv->conf_file = nm_config_data_get_config_main_file (nm_config_get_data (nm_config_get ())); - - /* plugin_set_hostname() has to be called *after* priv->conf_file is set */ - priv->hostname = plugin_get_hostname (singleton); - } else - g_object_ref (singleton); - - return G_OBJECT (singleton); + return g_object_new (SETTINGS_TYPE_PLUGIN_KEYFILE, NULL); } diff --git a/src/settings/plugins/keyfile/plugin.h b/src/settings/plugins/keyfile/plugin.h index 48579785..07403270 100644 --- a/src/settings/plugins/keyfile/plugin.h +++ b/src/settings/plugins/keyfile/plugin.h @@ -22,24 +22,24 @@ #ifndef _PLUGIN_H_ #define _PLUGIN_H_ -#include +#include "nm-default.h" -#define SC_TYPE_PLUGIN_KEYFILE (sc_plugin_keyfile_get_type ()) -#define SC_PLUGIN_KEYFILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_KEYFILE, SCPluginKeyfile)) -#define SC_PLUGIN_KEYFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_KEYFILE, SCPluginKeyfileClass)) -#define SC_IS_PLUGIN_KEYFILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_KEYFILE)) -#define SC_IS_PLUGIN_KEYFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_PLUGIN_KEYFILE)) -#define SC_PLUGIN_KEYFILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_KEYFILE, SCPluginKeyfileClass)) +#define SETTINGS_TYPE_PLUGIN_KEYFILE (settings_plugin_keyfile_get_type ()) +#define SETTINGS_PLUGIN_KEYFILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SETTINGS_TYPE_PLUGIN_KEYFILE, SettingsPluginKeyfile)) +#define SETTINGS_PLUGIN_KEYFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SETTINGS_TYPE_PLUGIN_KEYFILE, SettingsPluginKeyfileClass)) +#define SETTINGS_IS_PLUGIN_KEYFILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SETTINGS_TYPE_PLUGIN_KEYFILE)) +#define SETTINGS_IS_PLUGIN_KEYFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SETTINGS_TYPE_PLUGIN_KEYFILE)) +#define SETTINGS_PLUGIN_KEYFILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SETTINGS_TYPE_PLUGIN_KEYFILE, SettingsPluginKeyfileClass)) typedef struct { GObject parent; -} SCPluginKeyfile; +} SettingsPluginKeyfile; typedef struct { GObjectClass parent; -} SCPluginKeyfileClass; +} SettingsPluginKeyfileClass; -GType sc_plugin_keyfile_get_type (void); +GType settings_plugin_keyfile_get_type (void); GObject *nm_settings_keyfile_plugin_new (void); diff --git a/src/settings/plugins/keyfile/reader.c b/src/settings/plugins/keyfile/reader.c index bd08c17d..1c984a16 100644 --- a/src/settings/plugins/keyfile/reader.c +++ b/src/settings/plugins/keyfile/reader.c @@ -25,7 +25,7 @@ #include "reader.h" -#include "nm-logging.h" +#include "nm-default.h" #include "nm-keyfile-internal.h" #include "NetworkManagerUtils.h" diff --git a/src/settings/plugins/keyfile/reader.h b/src/settings/plugins/keyfile/reader.h index 55819630..a8021cb7 100644 --- a/src/settings/plugins/keyfile/reader.h +++ b/src/settings/plugins/keyfile/reader.h @@ -22,9 +22,10 @@ #ifndef _KEYFILE_PLUGIN_READER_H #define _KEYFILE_PLUGIN_READER_H -#include #include +#include "nm-default.h" + NMConnection *nm_keyfile_plugin_connection_from_file (const char *filename, GError **error); #endif /* _KEYFILE_PLUGIN_READER_H */ diff --git a/src/settings/plugins/keyfile/tests/Makefile.am b/src/settings/plugins/keyfile/tests/Makefile.am index cbe3f73b..4d85f09a 100644 --- a/src/settings/plugins/keyfile/tests/Makefile.am +++ b/src/settings/plugins/keyfile/tests/Makefile.am @@ -5,18 +5,17 @@ SUBDIRS=keyfiles @GNOME_CODE_COVERAGE_RULES@ AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/settings \ -I$(srcdir)/../ \ $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) \ $(CODE_COVERAGE_CFLAGS) \ -DG_LOG_DOMAIN=\""NetworkManager-keyfile"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ -DTEST_KEYFILES_DIR=\"$(abs_srcdir)/keyfiles\" \ -DTEST_SCRATCH_DIR=\"$(abs_builddir)/keyfiles\" \ @@ -32,7 +31,6 @@ test_keyfile_SOURCES = \ test_keyfile_LDADD = \ $(top_builddir)/src/libNetworkManager.la \ - $(DBUS_LIBS) \ $(CODE_COVERAGE_LDFLAGS) @VALGRIND_RULES@ diff --git a/src/settings/plugins/keyfile/tests/Makefile.in b/src/settings/plugins/keyfile/tests/Makefile.in index 6dfaf110..7577df57 100644 --- a/src/settings/plugins/keyfile/tests/Makefile.in +++ b/src/settings/plugins/keyfile/tests/Makefile.in @@ -122,7 +122,7 @@ test_keyfile_OBJECTS = $(am_test_keyfile_OBJECTS) am__DEPENDENCIES_1 = @ENABLE_TESTS_TRUE@test_keyfile_DEPENDENCIES = \ @ENABLE_TESTS_TRUE@ $(top_builddir)/src/libNetworkManager.la \ -@ENABLE_TESTS_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +@ENABLE_TESTS_TRUE@ $(am__DEPENDENCIES_1) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent @@ -450,7 +450,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -462,8 +461,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -473,6 +470,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -527,16 +525,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -573,6 +568,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -601,7 +598,6 @@ 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@ @@ -616,6 +612,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -676,6 +674,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -683,6 +682,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -700,18 +700,17 @@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ @ENABLE_TESTS_TRUE@SUBDIRS = keyfiles @ENABLE_TESTS_TRUE@AM_CPPFLAGS = \ -@ENABLE_TESTS_TRUE@ -I$(top_srcdir)/include \ -@ENABLE_TESTS_TRUE@ -I$(top_builddir)/include \ +@ENABLE_TESTS_TRUE@ -I$(top_srcdir)/shared \ +@ENABLE_TESTS_TRUE@ -I$(top_builddir)/shared \ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/libnm-core \ @ENABLE_TESTS_TRUE@ -I$(top_builddir)/libnm-core \ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/src \ @ENABLE_TESTS_TRUE@ -I$(top_srcdir)/src/settings \ @ENABLE_TESTS_TRUE@ -I$(srcdir)/../ \ @ENABLE_TESTS_TRUE@ $(GLIB_CFLAGS) \ -@ENABLE_TESTS_TRUE@ $(DBUS_CFLAGS) \ @ENABLE_TESTS_TRUE@ $(CODE_COVERAGE_CFLAGS) \ @ENABLE_TESTS_TRUE@ -DG_LOG_DOMAIN=\""NetworkManager-keyfile"\" \ -@ENABLE_TESTS_TRUE@ -DNETWORKMANAGER_COMPILATION \ +@ENABLE_TESTS_TRUE@ -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ @ENABLE_TESTS_TRUE@ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ @ENABLE_TESTS_TRUE@ -DTEST_KEYFILES_DIR=\"$(abs_srcdir)/keyfiles\" \ @ENABLE_TESTS_TRUE@ -DTEST_SCRATCH_DIR=\"$(abs_builddir)/keyfiles\" \ @@ -725,7 +724,6 @@ with_valgrind = @with_valgrind@ @ENABLE_TESTS_TRUE@test_keyfile_LDADD = \ @ENABLE_TESTS_TRUE@ $(top_builddir)/src/libNetworkManager.la \ -@ENABLE_TESTS_TRUE@ $(DBUS_LIBS) \ @ENABLE_TESTS_TRUE@ $(CODE_COVERAGE_LDFLAGS) all: all-recursive diff --git a/src/settings/plugins/keyfile/tests/keyfiles/ATT_Data_Connect_Plain b/src/settings/plugins/keyfile/tests/keyfiles/ATT_Data_Connect_Plain index 902b8427..11e1ec6f 100644 --- a/src/settings/plugins/keyfile/tests/keyfiles/ATT_Data_Connect_Plain +++ b/src/settings/plugins/keyfile/tests/keyfiles/ATT_Data_Connect_Plain @@ -15,6 +15,9 @@ password=CINGULAR1 apn=ISP.CINGULAR network-id=24005 pin=2345 +device-id=da812de91eec16620b06cd0ca5cbc7ea25245222 +sim-id=89148000000060671234 +sim-operator-id=310260 [serial] baud=115200 diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in index 33d0e0c5..56f0735f 100644 --- a/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in +++ b/src/settings/plugins/keyfile/tests/keyfiles/Makefile.in @@ -146,7 +146,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -158,8 +157,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -169,6 +166,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -223,16 +221,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -269,6 +264,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -297,7 +294,6 @@ 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@ @@ -312,6 +308,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -372,6 +370,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -379,6 +378,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ diff --git a/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main b/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main index 3b9fcb28..fc9fd8f8 100644 --- a/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main +++ b/src/settings/plugins/keyfile/tests/keyfiles/Test_Bridge_Main @@ -11,6 +11,7 @@ priority=32744 hello-time=7 max-age=39 ageing-time=235352 +multicast-snooping=false [ipv4] method=auto diff --git a/src/settings/plugins/keyfile/tests/test-keyfile.c b/src/settings/plugins/keyfile/tests/test-keyfile.c index 785ad4cb..250bad36 100644 --- a/src/settings/plugins/keyfile/tests/test-keyfile.c +++ b/src/settings/plugins/keyfile/tests/test-keyfile.c @@ -29,7 +29,7 @@ #include #include "nm-core-internal.h" -#include "nm-logging.h" +#include "nm-default.h" #include "reader.h" #include "writer.h" @@ -1882,153 +1882,43 @@ test_read_gsm_connection (void) NMSettingConnection *s_con; NMSettingSerial *s_serial; NMSettingGsm *s_gsm; - NMSettingBluetooth *s_bluetooth; GError *error = NULL; - const char *tmp; - NMSettingSerialParity parity; - const char *expected_id = "AT&T Data Connect"; - const char *expected_apn = "ISP.CINGULAR"; - const char *expected_username = "ISP@CINGULARGPRS.COM"; - const char *expected_password = "CINGULAR1"; - const char *expected_network_id = "24005"; - const char *expected_pin = "2345"; + gboolean success; - connection = nm_keyfile_plugin_connection_from_file (TEST_GSM_FILE, NULL); - ASSERT (connection != NULL, - "connection-read", "failed to read %s", TEST_GSM_FILE); + connection = nm_keyfile_plugin_connection_from_file (TEST_GSM_FILE, &error); + g_assert_no_error (error); + g_assert (connection); - ASSERT (nm_connection_verify (connection, &error), - "connection-verify", "failed to verify %s: %s", TEST_GSM_FILE, error->message); + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); /* ===== CONNECTION SETTING ===== */ - s_con = nm_connection_get_setting_connection (connection); - ASSERT (s_con != NULL, - "connection-verify-connection", "failed to verify %s: missing %s setting", - TEST_GSM_FILE, - NM_SETTING_CONNECTION_SETTING_NAME); - - /* ID */ - tmp = nm_setting_connection_get_id (s_con); - ASSERT (tmp != NULL, - "connection-verify-connection", "failed to verify %s: missing %s / %s key", - TEST_GSM_FILE, - NM_SETTING_CONNECTION_SETTING_NAME, - NM_SETTING_CONNECTION_ID); - ASSERT (strcmp (tmp, expected_id) == 0, - "connection-verify-connection", "failed to verify %s: unexpected %s / %s key value", - TEST_GSM_FILE, - NM_SETTING_CONNECTION_SETTING_NAME, - NM_SETTING_CONNECTION_ID); - - tmp = nm_setting_connection_get_connection_type (s_con); - ASSERT (tmp != NULL, - "connection-verify-connection", "failed to verify %s: missing %s / %s key", - TEST_GSM_FILE, - NM_SETTING_CONNECTION_SETTING_NAME, - NM_SETTING_CONNECTION_ID); - ASSERT (strcmp (tmp, NM_SETTING_GSM_SETTING_NAME) == 0, - "connection-verify-connection", "failed to verify %s: unexpected %s / %s key value", - TEST_GSM_FILE, - NM_SETTING_CONNECTION_SETTING_NAME, - NM_SETTING_CONNECTION_TYPE); + g_assert (s_con); + g_assert_cmpstr (nm_setting_connection_get_id (s_con), ==, "AT&T Data Connect"); + g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_GSM_SETTING_NAME); /* ===== BLUETOOTH SETTING ===== */ - /* Plain GSM, so no BT setting expected */ - s_bluetooth = nm_connection_get_setting_bluetooth (connection); - ASSERT (s_bluetooth == NULL, - "connection-verify-bt", "unexpected %s setting", - TEST_GSM_FILE, - NM_SETTING_BLUETOOTH_SETTING_NAME); + g_assert (nm_connection_get_setting_bluetooth (connection) == NULL); /* ===== GSM SETTING ===== */ - s_gsm = nm_connection_get_setting_gsm (connection); - ASSERT (s_gsm != NULL, - "connection-verify-gsm", "failed to verify %s: missing %s setting", - TEST_GSM_FILE, - NM_SETTING_GSM_SETTING_NAME); - - /* APN */ - tmp = nm_setting_gsm_get_apn (s_gsm); - ASSERT (tmp != NULL, - "connection-verify-gsm", "failed to verify %s: missing %s / %s key", - TEST_GSM_FILE, - NM_SETTING_GSM_SETTING_NAME, - NM_SETTING_GSM_APN); - ASSERT (strcmp (tmp, expected_apn) == 0, - "connection-verify-gsm", "failed to verify %s: unexpected %s / %s key value", - TEST_GSM_FILE, - NM_SETTING_GSM_SETTING_NAME, - NM_SETTING_GSM_APN); - - /* Username */ - tmp = nm_setting_gsm_get_username (s_gsm); - ASSERT (tmp != NULL, - "connection-verify-gsm", "failed to verify %s: missing %s / %s key", - TEST_GSM_FILE, - NM_SETTING_GSM_SETTING_NAME, - NM_SETTING_GSM_USERNAME); - ASSERT (strcmp (tmp, expected_username) == 0, - "connection-verify-gsm", "failed to verify %s: unexpected %s / %s key value", - TEST_GSM_FILE, - NM_SETTING_GSM_SETTING_NAME, - NM_SETTING_GSM_USERNAME); - - /* Password */ - tmp = nm_setting_gsm_get_password (s_gsm); - ASSERT (tmp != NULL, - "connection-verify-gsm", "failed to verify %s: missing %s / %s key", - TEST_GSM_FILE, - NM_SETTING_GSM_SETTING_NAME, - NM_SETTING_GSM_PASSWORD); - ASSERT (strcmp (tmp, expected_password) == 0, - "connection-verify-gsm", "failed to verify %s: unexpected %s / %s key value", - TEST_GSM_FILE, - NM_SETTING_GSM_SETTING_NAME, - NM_SETTING_GSM_PASSWORD); - - /* Network ID */ - tmp = nm_setting_gsm_get_network_id (s_gsm); - ASSERT (tmp != NULL, - "connection-verify-gsm", "failed to verify %s: missing %s / %s key", - TEST_GSM_FILE, - NM_SETTING_GSM_SETTING_NAME, - NM_SETTING_GSM_NETWORK_ID); - ASSERT (strcmp (tmp, expected_network_id) == 0, - "connection-verify-gsm", "failed to verify %s: unexpected %s / %s key value", - TEST_GSM_FILE, - NM_SETTING_GSM_SETTING_NAME, - NM_SETTING_GSM_NETWORK_ID); - - /* PIN */ - tmp = nm_setting_gsm_get_pin (s_gsm); - ASSERT (tmp != NULL, - "connection-verify-gsm", "failed to verify %s: missing %s / %s key", - TEST_GSM_FILE, - NM_SETTING_GSM_SETTING_NAME, - NM_SETTING_GSM_PIN); - ASSERT (strcmp (tmp, expected_pin) == 0, - "connection-verify-gsm", "failed to verify %s: unexpected %s / %s key value", - TEST_GSM_FILE, - NM_SETTING_GSM_SETTING_NAME, - NM_SETTING_GSM_PIN); + g_assert (s_gsm); + g_assert_cmpstr (nm_setting_gsm_get_apn (s_gsm), ==, "ISP.CINGULAR"); + g_assert_cmpstr (nm_setting_gsm_get_username (s_gsm), ==, "ISP@CINGULARGPRS.COM"); + g_assert_cmpstr (nm_setting_gsm_get_password (s_gsm), ==, "CINGULAR1"); + g_assert_cmpstr (nm_setting_gsm_get_network_id (s_gsm), ==, "24005"); + g_assert_cmpstr (nm_setting_gsm_get_pin (s_gsm), ==, "2345"); + g_assert_cmpstr (nm_setting_gsm_get_device_id (s_gsm), ==, "da812de91eec16620b06cd0ca5cbc7ea25245222"); + g_assert_cmpstr (nm_setting_gsm_get_sim_id (s_gsm), ==, "89148000000060671234"); + g_assert_cmpstr (nm_setting_gsm_get_sim_operator_id (s_gsm), ==, "310260"); /* ===== SERIAL SETTING ===== */ - s_serial = nm_connection_get_setting_serial (connection); - ASSERT (s_serial != NULL, - "connection-verify-serial", "failed to verify %s: missing %s setting", - TEST_GSM_FILE, - NM_SETTING_SERIAL_SETTING_NAME); - - parity = nm_setting_serial_get_parity (s_serial); - ASSERT (parity == NM_SETTING_SERIAL_PARITY_ODD, - "connection-verify-serial", "failed to verify %s: unexpected %s / %s key value", - TEST_GSM_FILE, - NM_SETTING_SERIAL_SETTING_NAME, - NM_SETTING_SERIAL_PARITY); + g_assert (s_serial); + g_assert_cmpint (nm_setting_serial_get_parity (s_serial), ==, NM_SETTING_SERIAL_PARITY_ODD); g_object_unref (connection); } @@ -2087,22 +1977,23 @@ test_write_gsm_connection (void) NM_SETTING_GSM_PIN, "123456", NM_SETTING_GSM_NETWORK_ID, "254098", NM_SETTING_GSM_HOME_ONLY, TRUE, + NM_SETTING_GSM_DEVICE_ID, "da812de91eec16620b06cd0ca5cbc7ea25245222", + NM_SETTING_GSM_SIM_ID, "89148000000060671234", + NM_SETTING_GSM_SIM_OPERATOR_ID, "310260", NULL); /* Write out the connection */ owner_uid = geteuid (); owner_grp = getegid (); success = nm_keyfile_plugin_write_test_connection (connection, TEST_SCRATCH_DIR, owner_uid, owner_grp, &testfile, &error); - ASSERT (success == TRUE, - "connection-write", "failed to write keyfile: %s", - error ? error->message : "(none)"); - - ASSERT (testfile != NULL, - "connection-write", "didn't get keyfile name back after writing connection"); + g_assert_no_error (error); + g_assert (success); + g_assert (testfile != NULL); /* Read the connection back in and compare it to the one we just wrote out */ - reread = nm_keyfile_plugin_connection_from_file (testfile, NULL); - ASSERT (reread != NULL, "connection-write", "failed to re-read test connection"); + reread = nm_keyfile_plugin_connection_from_file (testfile, &error); + g_assert_no_error (error); + g_assert (reread); nmtst_assert_connection_equals (connection, TRUE, reread, FALSE); @@ -2821,6 +2712,7 @@ test_read_bridge_main (void) g_assert_cmpuint (nm_setting_bridge_get_hello_time (s_bridge), ==, 7); g_assert_cmpuint (nm_setting_bridge_get_max_age (s_bridge), ==, 39); g_assert_cmpuint (nm_setting_bridge_get_ageing_time (s_bridge), ==, 235352); + g_assert_cmpuint (nm_setting_bridge_get_multicast_snooping (s_bridge), ==, FALSE); g_object_unref (connection); } diff --git a/src/settings/plugins/keyfile/utils.c b/src/settings/plugins/keyfile/utils.c index 4809c642..48795ffb 100644 --- a/src/settings/plugins/keyfile/utils.c +++ b/src/settings/plugins/keyfile/utils.c @@ -20,15 +20,16 @@ #include "config.h" -#include #include #include -#include "gsystem-local-alloc.h" +#include "nm-default.h" #include "utils.h" #include #include #include +#include "nm-config.h" +#define NM_CONFIG_KEYFILE_PATH_DEFAULT NMCONFDIR "/system-connections" static const char temp_letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; @@ -146,3 +147,23 @@ nm_keyfile_plugin_utils_escape_filename (const char *filename) return g_string_free (str, FALSE);; } +/*****************************************************************************/ + +const char * +nm_keyfile_plugin_get_path (void) +{ + static char *path = NULL; + + if (G_UNLIKELY (!path)) { + path = nm_config_data_get_value (NM_CONFIG_GET_DATA_ORIG, + NM_CONFIG_KEYFILE_GROUP_KEYFILE, + NM_CONFIG_KEYFILE_KEY_KEYFILE_PATH, + NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY); + if (!path) + path = g_strdup (""NM_CONFIG_KEYFILE_PATH_DEFAULT""); + } + return path; +} + +/*****************************************************************************/ + diff --git a/src/settings/plugins/keyfile/utils.h b/src/settings/plugins/keyfile/utils.h index d0862284..0b2b6f4e 100644 --- a/src/settings/plugins/keyfile/utils.h +++ b/src/settings/plugins/keyfile/utils.h @@ -21,9 +21,12 @@ #ifndef _UTILS_H_ #define _UTILS_H_ -#include +#include "nm-default.h" #include "NetworkManagerUtils.h" +#define KEYFILE_PLUGIN_NAME "keyfile" +#define KEYFILE_PLUGIN_INFO "(c) 2007 - 2015 Red Hat, Inc. To report bugs please use the NetworkManager mailing list." + #define NM_KEYFILE_CONNECTION_LOG_PATH(path) str_if_set (path,"in-memory") #define NM_KEYFILE_CONNECTION_LOG_FMT "%s (%s,\"%s\")" #define NM_KEYFILE_CONNECTION_LOG_ARG(con) NM_KEYFILE_CONNECTION_LOG_PATH (nm_settings_connection_get_filename ((NMSettingsConnection *) (con))), nm_connection_get_uuid ((NMConnection *) (con)), nm_connection_get_id ((NMConnection *) (con)) @@ -34,5 +37,7 @@ gboolean nm_keyfile_plugin_utils_should_ignore_file (const char *filename); char *nm_keyfile_plugin_utils_escape_filename (const char *filename); +const char *nm_keyfile_plugin_get_path (void); + #endif /* _UTILS_H_ */ diff --git a/src/settings/plugins/keyfile/writer.c b/src/settings/plugins/keyfile/writer.c index b6a8786d..db00b061 100644 --- a/src/settings/plugins/keyfile/writer.c +++ b/src/settings/plugins/keyfile/writer.c @@ -27,15 +27,11 @@ #include #include -#include "nm-glib-compat.h" - -#include "nm-logging.h" +#include "nm-default.h" #include "writer.h" -#include "common.h" #include "utils.h" #include "nm-keyfile-internal.h" - typedef struct { const char *keyfile_dir; } WriteInfo; @@ -233,17 +229,18 @@ _internal_write_connection (NMConnection *connection, uid_t owner_uid, pid_t owner_grp, const char *existing_path, + gboolean force_rename, char **out_path, GError **error) { GKeyFile *key_file; - char *data; + gs_free char *data = NULL; gsize len; - gboolean success = FALSE; - char *path; + gs_free char *path = NULL; const char *id; WriteInfo info = { 0 }; GError *local_err = NULL; + int errsv; g_return_val_if_fail (!out_path || !*out_path, FALSE); g_return_val_if_fail (keyfile_dir && keyfile_dir[0] == '/', FALSE); @@ -267,7 +264,7 @@ _internal_write_connection (NMConnection *connection, /* If we have existing file path, use it. Else generate one from * connection's ID. */ - if (existing_path != NULL) { + if (existing_path != NULL && !force_rename) { path = g_strdup (existing_path); } else { char *filename_escaped = nm_keyfile_plugin_utils_escape_filename (id); @@ -312,8 +309,7 @@ _internal_write_connection (NMConnection *connection, /* this really should not happen, we tried hard to find an unused name... bail out. */ g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, "could not find suitable keyfile file name (%s already used)", path); - g_free (path); - goto out; + return FALSE; } /* Both our preferred path based on connection id and id-uuid are taken. * Fallback to @existing_path */ @@ -331,49 +327,49 @@ _internal_write_connection (NMConnection *connection, g_file_set_contents (path, data, len, &local_err); if (local_err) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "%s.%d: error writing to file '%s': %s", __FILE__, __LINE__, + "error writing to file '%s': %s", path, local_err->message); g_error_free (local_err); - g_free (path); - goto out; + return FALSE; } if (chown (path, owner_uid, owner_grp) < 0) { + errsv = errno; g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "%s.%d: error chowning '%s': %d", __FILE__, __LINE__, - path, errno); + "error chowning '%s': %s (%d)", + path, g_strerror (errsv), errsv); unlink (path); - } else { - if (chmod (path, S_IRUSR | S_IWUSR) < 0) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, - "%s.%d: error setting permissions on '%s': %d", __FILE__, - __LINE__, path, errno); - unlink (path); - } else { - if (out_path && g_strcmp0 (existing_path, path)) { - *out_path = path; /* pass path out to caller */ - path = NULL; - } - success = TRUE; - } + return FALSE; } - g_free (path); -out: - g_free (data); - return success; + if (chmod (path, S_IRUSR | S_IWUSR) < 0) { + errsv = errno; + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_FAILED, + "error setting permissions on '%s': %s (%d)", + path, g_strerror (errsv), errsv); + unlink (path); + return FALSE; + } + + if (out_path && g_strcmp0 (existing_path, path)) { + *out_path = path; /* pass path out to caller */ + path = NULL; + } + return TRUE; } gboolean nm_keyfile_plugin_write_connection (NMConnection *connection, const char *existing_path, + gboolean force_rename, char **out_path, GError **error) { return _internal_write_connection (connection, - KEYFILE_DIR, + nm_keyfile_plugin_get_path (), 0, 0, existing_path, + force_rename, out_path, error); } @@ -390,6 +386,7 @@ nm_keyfile_plugin_write_test_connection (NMConnection *connection, keyfile_dir, owner_uid, owner_grp, NULL, + FALSE, out_path, error); } diff --git a/src/settings/plugins/keyfile/writer.h b/src/settings/plugins/keyfile/writer.h index 8b08812d..25f44e94 100644 --- a/src/settings/plugins/keyfile/writer.h +++ b/src/settings/plugins/keyfile/writer.h @@ -22,11 +22,13 @@ #ifndef _KEYFILE_PLUGIN_WRITER_H #define _KEYFILE_PLUGIN_WRITER_H -#include #include +#include "nm-default.h" + gboolean nm_keyfile_plugin_write_connection (NMConnection *connection, const char *existing_path, + gboolean force_rename, char **out_path, GError **error); diff --git a/src/supplicant-manager/nm-supplicant-config.c b/src/supplicant-manager/nm-supplicant-config.c index 692efef3..190ee0a7 100644 --- a/src/supplicant-manager/nm-supplicant-config.c +++ b/src/supplicant-manager/nm-supplicant-config.c @@ -23,12 +23,10 @@ #include #include -#include -#include +#include "nm-default.h" #include "nm-supplicant-config.h" #include "nm-supplicant-settings-verify.h" -#include "nm-logging.h" #include "nm-setting.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" @@ -41,7 +39,7 @@ G_DEFINE_TYPE (NMSupplicantConfig, nm_supplicant_config, G_TYPE_OBJECT) typedef struct { char *value; - guint32 len; + guint32 len; OptType type; } ConfigOption; @@ -50,6 +48,7 @@ typedef struct GHashTable *config; GHashTable *blobs; guint32 ap_scan; + NMSettingMacRandomization mac_randomization; gboolean fast_required; gboolean dispose_has_run; } NMSupplicantConfigPrivate; @@ -87,6 +86,7 @@ nm_supplicant_config_init (NMSupplicantConfig * self) (GDestroyNotify) blob_free); priv->ap_scan = 1; + priv->mac_randomization = NM_SETTING_MAC_RANDOMIZATION_DEFAULT; priv->dispose_has_run = FALSE; } @@ -96,7 +96,8 @@ nm_supplicant_config_add_option_with_type (NMSupplicantConfig *self, const char *value, gint32 len, OptType opt_type, - gboolean secret) + gboolean secret, + GError **error) { NMSupplicantConfigPrivate *priv; ConfigOption *old_opt; @@ -106,6 +107,7 @@ nm_supplicant_config_add_option_with_type (NMSupplicantConfig *self, g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE); g_return_val_if_fail (key != NULL, FALSE); g_return_val_if_fail (value != NULL, FALSE); + nm_assert (!error || !*error); priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self); @@ -120,23 +122,26 @@ nm_supplicant_config_add_option_with_type (NMSupplicantConfig *self, char buf[255]; memset (&buf[0], 0, sizeof (buf)); memcpy (&buf[0], value, len > 254 ? 254 : len); - nm_log_warn (LOGD_SUPPLICANT, "Key '%s' and/or value '%s' invalid.", key, secret ? "" : buf); + g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "key '%s' and/or value '%s' invalid", key, secret ? "" : buf); return FALSE; } } old_opt = (ConfigOption *) g_hash_table_lookup (priv->config, key); if (old_opt) { - nm_log_warn (LOGD_SUPPLICANT, "Key '%s' already in table.", key); + g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "key '%s' already configured", key); return FALSE; } opt = g_slice_new0 (ConfigOption); - opt->value = g_malloc0 ((sizeof (char) * len) + 1); + opt->value = g_malloc (len + 1); memcpy (opt->value, value, len); + opt->value[len] = '\0'; opt->len = len; - opt->type = type; + opt->type = type; { char buf[255]; @@ -155,16 +160,18 @@ nm_supplicant_config_add_option (NMSupplicantConfig *self, const char *key, const char *value, gint32 len, - gboolean secret) + gboolean secret, + GError **error) { - return nm_supplicant_config_add_option_with_type (self, key, value, len, TYPE_INVALID, secret); + return nm_supplicant_config_add_option_with_type (self, key, value, len, TYPE_INVALID, secret, error); } static gboolean nm_supplicant_config_add_blob (NMSupplicantConfig *self, const char *key, GBytes *value, - const char *blobid) + const char *blobid, + GError **error) { NMSupplicantConfigPrivate *priv; ConfigOption *old_opt; @@ -186,13 +193,15 @@ nm_supplicant_config_add_blob (NMSupplicantConfig *self, type = nm_supplicant_settings_verify_setting (key, (const char *) data, data_len); if (type == TYPE_INVALID) { - nm_log_warn (LOGD_SUPPLICANT, "Key '%s' and/or it's contained value is invalid.", key); + g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "key '%s' and/or its contained value is invalid", key); return FALSE; } old_opt = (ConfigOption *) g_hash_table_lookup (priv->config, key); if (old_opt) { - nm_log_warn (LOGD_SUPPLICANT, "Key '%s' already in table.", key); + g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "key '%s' already configured", key); return FALSE; } @@ -202,7 +211,7 @@ nm_supplicant_config_add_blob (NMSupplicantConfig *self, opt = g_slice_new0 (ConfigOption); opt->value = g_strdup_printf ("blob://%s", blobid); opt->len = strlen (opt->value); - opt->type = type; + opt->type = type; nm_log_info (LOGD_SUPPLICANT, "Config: added '%s' value '%s'", key, opt->value); @@ -212,6 +221,28 @@ nm_supplicant_config_add_blob (NMSupplicantConfig *self, return TRUE; } +static gboolean +nm_supplicant_config_add_blob_for_connection (NMSupplicantConfig *self, + GBytes *field, + const char *name, + const char *con_uid, + GError **error) +{ + if (field && g_bytes_get_size (field)) { + gs_free char *uid = NULL; + char *p; + + uid = g_strdup_printf ("%s-%s", con_uid, name); + for (p = uid; *p; p++) { + if (*p == '/') + *p = '-'; + } + if (!nm_supplicant_config_add_blob (self, name, field, uid, error)) + return FALSE; + } + return TRUE; +} + static void nm_supplicant_config_finalize (GObject *object) { @@ -242,14 +273,30 @@ nm_supplicant_config_get_ap_scan (NMSupplicantConfig * self) return NM_SUPPLICANT_CONFIG_GET_PRIVATE (self)->ap_scan; } -void -nm_supplicant_config_set_ap_scan (NMSupplicantConfig * self, - guint32 ap_scan) +const char * +nm_supplicant_config_get_mac_randomization (NMSupplicantConfig *self) { - g_return_if_fail (NM_IS_SUPPLICANT_CONFIG (self)); - g_return_if_fail (ap_scan <= 2); + g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), 0); + + /** + * mac_addr - MAC address policy default + * + * 0 = use permanent MAC address + * 1 = use random MAC address for each ESS connection + * 2 = like 1, but maintain OUI (with local admin bit set) + * + * By default, permanent MAC address is used unless policy is changed by + * the per-network mac_addr parameter. + */ - NM_SUPPLICANT_CONFIG_GET_PRIVATE (self)->ap_scan = ap_scan; + switch (NM_SUPPLICANT_CONFIG_GET_PRIVATE (self)->mac_randomization) { + case NM_SETTING_MAC_RANDOMIZATION_ALWAYS: + return "1"; + case NM_SETTING_MAC_RANDOMIZATION_NEVER: + case NM_SETTING_MAC_RANDOMIZATION_DEFAULT: + default: + return "0"; + } } gboolean @@ -338,7 +385,10 @@ wifi_freqs_to_string (gboolean bg_band) gboolean nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, NMSettingWireless * setting, - guint32 fixed_freq) + guint32 fixed_freq, + NMSupplicantFeature mac_randomization_support, + NMSettingMacRandomization mac_randomization_fallback, + GError **error) { NMSupplicantConfigPrivate *priv; gboolean is_adhoc, is_ap; @@ -349,6 +399,7 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE); g_return_val_if_fail (setting != NULL, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); priv = NM_SUPPLICANT_CONFIG_GET_PRIVATE (self); @@ -364,42 +415,33 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, if (!nm_supplicant_config_add_option (self, "ssid", (char *) g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid), - FALSE)) { - nm_log_warn (LOGD_SUPPLICANT, "Error adding SSID to supplicant config."); + FALSE, + error)) return FALSE; - } if (is_adhoc) { - if (!nm_supplicant_config_add_option (self, "mode", "1", -1, FALSE)) { - nm_log_warn (LOGD_SUPPLICANT, "Error adding mode=1 (adhoc) to supplicant config."); + if (!nm_supplicant_config_add_option (self, "mode", "1", -1, FALSE, error)) return FALSE; - } } if (is_ap) { - if (!nm_supplicant_config_add_option (self, "mode", "2", -1, FALSE)) { - nm_log_warn (LOGD_SUPPLICANT, "Error adding mode=2 (ap) to supplicant config."); + if (!nm_supplicant_config_add_option (self, "mode", "2", -1, FALSE, error)) return FALSE; - } } if ((is_adhoc || is_ap) && fixed_freq) { - char *str_freq; + gs_free char *str_freq = NULL; str_freq = g_strdup_printf ("%u", fixed_freq); - if (!nm_supplicant_config_add_option (self, "frequency", str_freq, -1, FALSE)) { - g_free (str_freq); - nm_log_warn (LOGD_SUPPLICANT, "Error adding Ad-Hoc/AP frequency to supplicant config."); + if (!nm_supplicant_config_add_option (self, "frequency", str_freq, -1, FALSE, error)) return FALSE; - } - g_free (str_freq); } /* Except for Ad-Hoc and Hotspot, request that the driver probe for the * specific SSID we want to associate with. */ if (!(is_adhoc || is_ap)) { - if (!nm_supplicant_config_add_option (self, "scan_ssid", "1", -1, FALSE)) + if (!nm_supplicant_config_add_option (self, "scan_ssid", "1", -1, FALSE, error)) return FALSE; } @@ -407,10 +449,9 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, if (bssid) { if (!nm_supplicant_config_add_option (self, "bssid", bssid, strlen (bssid), - FALSE)) { - nm_log_warn (LOGD_SUPPLICANT, "Error adding BSSID to supplicant config."); + FALSE, + error)) return FALSE; - } } band = nm_setting_wireless_get_band (setting); @@ -418,16 +459,12 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, if (band) { if (channel) { guint32 freq; - char *str_freq; + gs_free char *str_freq = NULL; freq = nm_utils_wifi_channel_to_freq (channel, band); str_freq = g_strdup_printf ("%u", freq); - if (!nm_supplicant_config_add_option (self, "freq_list", str_freq, -1, FALSE)) { - g_free (str_freq); - nm_log_warn (LOGD_SUPPLICANT, "Error adding frequency list to supplicant config."); + if (!nm_supplicant_config_add_option (self, "freq_list", str_freq, -1, FALSE, error)) return FALSE; - } - g_free (str_freq); } else { const char *freqs = NULL; @@ -436,13 +473,28 @@ nm_supplicant_config_add_setting_wireless (NMSupplicantConfig * self, else if (!strcmp (band, "bg")) freqs = wifi_freqs_to_string (TRUE); - if (freqs && !nm_supplicant_config_add_option (self, "freq_list", freqs, strlen (freqs), FALSE)) { - nm_log_warn (LOGD_SUPPLICANT, "Error adding frequency list/band to supplicant config."); + if (freqs && !nm_supplicant_config_add_option (self, "freq_list", freqs, strlen (freqs), FALSE, error)) return FALSE; - } } } + priv->mac_randomization = nm_setting_wireless_get_mac_address_randomization (setting); + if (priv->mac_randomization == NM_SETTING_MAC_RANDOMIZATION_DEFAULT) { + priv->mac_randomization = mac_randomization_fallback; + if (priv->mac_randomization == NM_SETTING_MAC_RANDOMIZATION_DEFAULT) { + /* Don't use randomization, unless explicitly enabled. + * Randomization can work badly with captive portals. */ + priv->mac_randomization = NM_SETTING_MAC_RANDOMIZATION_NEVER; + } + } + + if ( priv->mac_randomization != NM_SETTING_MAC_RANDOMIZATION_NEVER + && mac_randomization_support != NM_SUPPLICANT_FEATURE_YES) { + g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "cannot enable mac-randomization due to missing supplicant support"); + return FALSE; + } + return TRUE; } @@ -451,73 +503,55 @@ add_string_val (NMSupplicantConfig *self, const char *field, const char *name, gboolean ucase, - gboolean secret) + gboolean secret, + GError **error) { - gboolean success; - char *value; - if (!field) - return TRUE; + if (field) { + gs_free char *value = NULL; - value = ucase ? g_ascii_strup (field, -1) : g_strdup (field); - success = nm_supplicant_config_add_option (self, name, value, strlen (field), secret); - if (!success) - nm_log_warn (LOGD_SUPPLICANT, "Error adding %s to supplicant config.", name); - g_free (value); - return success; + if (ucase) { + value = g_ascii_strup (field, -1); + field = value; + } + return nm_supplicant_config_add_option (self, name, field, strlen (field), secret, error); + } + return TRUE; } -#define ADD_STRING_LIST_VAL(setting, setting_name, field, field_plural, name, separator, ucase, secret) \ - if (nm_setting_##setting_name##_get_num_##field_plural (setting)) { \ - guint32 k; \ - GString *str = g_string_new (NULL); \ - for (k = 0; k < nm_setting_##setting_name##_get_num_##field_plural (setting); k++) { \ - const char *item = nm_setting_##setting_name##_get_##field (setting, k); \ - if (!str->len) { \ - g_string_append (str, item); \ - } else { \ - g_string_append_c (str, separator); \ - g_string_append (str, item); \ +#define ADD_STRING_LIST_VAL(self, setting, setting_name, field, field_plural, name, separator, ucase, secret, error) \ + ({ \ + typeof (*(setting)) *_setting = (setting); \ + gboolean _success = TRUE; \ + \ + if (nm_setting_##setting_name##_get_num_##field_plural (_setting)) { \ + const char _separator = (separator); \ + GString *_str = g_string_new (NULL); \ + guint _k, _n; \ + \ + _n = nm_setting_##setting_name##_get_num_##field_plural (_setting); \ + for (_k = 0; _k < _n; _k++) { \ + const char *item = nm_setting_##setting_name##_get_##field (_setting, _k); \ + \ + if (!_str->len) { \ + g_string_append (_str, item); \ + } else { \ + g_string_append_c (_str, _separator); \ + g_string_append (_str, item); \ + } \ } \ + if ((ucase)) \ + g_string_ascii_up (_str); \ + if (_str->len) { \ + if (!nm_supplicant_config_add_option ((self), (name), _str->str, -1, (secret), (error))) \ + _success = FALSE; \ + } \ + g_string_free (_str, TRUE); \ } \ - if (ucase) \ - g_string_ascii_up (str); \ - if (str->len) \ - success = nm_supplicant_config_add_option (self, name, str->str, -1, secret); \ - else \ - success = TRUE; \ - g_string_free (str, TRUE); \ - if (!success) { \ - nm_log_warn (LOGD_SUPPLICANT, "Error adding %s to supplicant config.", name); \ - return FALSE; \ - } \ - } + _success; \ + }) -static char * -get_blob_id (const char *name, const char *seed_uid) -{ - char *uid = g_strdup_printf ("%s-%s", seed_uid, name); - char *p = uid; - while (*p) { - if (*p == '/') *p = '-'; - p++; - } - return uid; -} - -#define ADD_BLOB_VAL(field, name, con_uid) \ - if (field && g_bytes_get_size (field)) { \ - char *uid = get_blob_id (name, con_uid); \ - success = nm_supplicant_config_add_blob (self, name, field, uid); \ - g_free (uid); \ - if (!success) { \ - nm_log_warn (LOGD_SUPPLICANT, "Error adding %s to supplicant config.", name); \ - return FALSE; \ - } \ - } - - -static gboolean +static void wep128_passphrase_hash (const char *input, size_t input_len, guint8 *out_digest, @@ -527,9 +561,9 @@ wep128_passphrase_hash (const char *input, guint8 data[64]; int i; - g_return_val_if_fail (out_digest != NULL, FALSE); - g_return_val_if_fail (out_digest_len != NULL, FALSE); - g_return_val_if_fail (*out_digest_len >= 16, FALSE); + g_return_if_fail (out_digest != NULL); + g_return_if_fail (out_digest_len != NULL); + g_return_if_fail (*out_digest_len >= 16); /* Get at least 64 bytes by repeating the passphrase into the buffer */ for (i = 0; i < sizeof (data); i++) @@ -544,17 +578,15 @@ wep128_passphrase_hash (const char *input, g_assert (*out_digest_len == 16); /* WEP104 keys are 13 bytes in length (26 hex characters) */ *out_digest_len = 13; - return TRUE; } static gboolean add_wep_key (NMSupplicantConfig *self, const char *key, const char *name, - NMWepKeyType wep_type) + NMWepKeyType wep_type, + GError **error) { - GBytes *bytes; - gboolean success = FALSE; size_t key_len = key ? strlen (key) : 0; if (!key || !key_len) @@ -570,39 +602,38 @@ add_wep_key (NMSupplicantConfig *self, if ( (wep_type == NM_WEP_KEY_TYPE_UNKNOWN) || (wep_type == NM_WEP_KEY_TYPE_KEY)) { if ((key_len == 10) || (key_len == 26)) { + gs_unref_bytes GBytes *bytes = NULL; + bytes = nm_utils_hexstr2bin (key); - if (bytes) { - success = nm_supplicant_config_add_option (self, - name, - g_bytes_get_data (bytes, NULL), - g_bytes_get_size (bytes), - TRUE); - g_bytes_unref (bytes); - } - if (!success) { - nm_log_warn (LOGD_SUPPLICANT, "Error adding %s to supplicant config.", name); + if (!bytes) { + g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "cannot add wep-key %s to suplicant config because key is not hex", + name); return FALSE; } + if (!nm_supplicant_config_add_option (self, + name, + g_bytes_get_data (bytes, NULL), + g_bytes_get_size (bytes), + TRUE, + error)) + return FALSE; } else if ((key_len == 5) || (key_len == 13)) { - if (!nm_supplicant_config_add_option (self, name, key, key_len, TRUE)) { - nm_log_warn (LOGD_SUPPLICANT, "Error adding %s to supplicant config.", name); + if (!nm_supplicant_config_add_option (self, name, key, key_len, TRUE, error)) return FALSE; - } } else { - nm_log_warn (LOGD_SUPPLICANT, "Invalid WEP key '%s'", name); + g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "Cannot add wep-key %s to suplicant config because key-length %u is invalid", + name, (guint) key_len); return FALSE; } } else if (wep_type == NM_WEP_KEY_TYPE_PASSPHRASE) { guint8 digest[16]; size_t digest_len = sizeof (digest); - success = wep128_passphrase_hash (key, key_len, digest, &digest_len); - if (success) - success = nm_supplicant_config_add_option (self, name, (const char *) digest, digest_len, TRUE); - if (!success) { - nm_log_warn (LOGD_SUPPLICANT, "Error adding %s to supplicant config.", name); + wep128_passphrase_hash (key, key_len, digest, &digest_len); + if (!nm_supplicant_config_add_option (self, name, (const char *) digest, digest_len, TRUE, error)) return FALSE; - } } return TRUE; @@ -613,22 +644,23 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, NMSettingWirelessSecurity *setting, NMSetting8021x *setting_8021x, const char *con_uuid, - guint32 mtu) + guint32 mtu, + GError **error) { - gboolean success = FALSE; const char *key_mgmt, *auth_alg; const char *psk; g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE); g_return_val_if_fail (setting != NULL, FALSE); g_return_val_if_fail (con_uuid != NULL, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); key_mgmt = nm_setting_wireless_security_get_key_mgmt (setting); - if (!add_string_val (self, key_mgmt, "key_mgmt", TRUE, FALSE)) + if (!add_string_val (self, key_mgmt, "key_mgmt", TRUE, FALSE, error)) return FALSE; auth_alg = nm_setting_wireless_security_get_auth_alg (setting); - if (!add_string_val (self, auth_alg, "auth_alg", TRUE, FALSE)) + if (!add_string_val (self, auth_alg, "auth_alg", TRUE, FALSE, error)) return FALSE; psk = nm_setting_wireless_security_get_psk (setting); @@ -636,35 +668,35 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, size_t psk_len = strlen (psk); if (psk_len == 64) { - GBytes *bytes; + gs_unref_bytes GBytes *bytes = NULL; /* Hex PSK */ bytes = nm_utils_hexstr2bin (psk); - if (bytes) { - success = nm_supplicant_config_add_option (self, - "psk", - g_bytes_get_data (bytes, NULL), - g_bytes_get_size (bytes), - TRUE); - g_bytes_unref (bytes); - } - if (!success) { - nm_log_warn (LOGD_SUPPLICANT, "Error adding 'psk' to supplicant config."); + if (!bytes) { + g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "Cannot add psk to supplicant config due to invalid hex"); return FALSE; } + + if (!nm_supplicant_config_add_option (self, + "psk", + g_bytes_get_data (bytes, NULL), + g_bytes_get_size (bytes), + TRUE, + error)) + return FALSE; } else if (psk_len >= 8 && psk_len <= 63) { /* Use TYPE_STRING here so that it gets pushed to the * supplicant as a string, and therefore gets quoted, * and therefore the supplicant will interpret it as a * passphrase and not a hex key. */ - if (!nm_supplicant_config_add_option_with_type (self, "psk", psk, -1, TYPE_STRING, TRUE)) { - nm_log_warn (LOGD_SUPPLICANT, "Error adding 'psk' to supplicant config."); + if (!nm_supplicant_config_add_option_with_type (self, "psk", psk, -1, TYPE_STRING, TRUE, error)) return FALSE; - } } else { - /* Invalid PSK */ - nm_log_warn (LOGD_SUPPLICANT, "Invalid PSK length %u: not between 8 and 63 characters inclusive.", (guint32) psk_len); + g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "Cannot add psk to supplicant config due to invalid PSK length %u (not between 8 and 63 characters)", + (guint) psk_len); return FALSE; } } @@ -673,9 +705,12 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, if ( !strcmp (key_mgmt, "wpa-none") || !strcmp (key_mgmt, "wpa-psk") || !strcmp (key_mgmt, "wpa-eap")) { - ADD_STRING_LIST_VAL (setting, wireless_security, proto, protos, "proto", ' ', TRUE, FALSE); - ADD_STRING_LIST_VAL (setting, wireless_security, pairwise, pairwise, "pairwise", ' ', TRUE, FALSE); - ADD_STRING_LIST_VAL (setting, wireless_security, group, groups, "group", ' ', TRUE, FALSE); + if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, proto, protos, "proto", ' ', TRUE, FALSE, error)) + return FALSE; + if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, pairwise, pairwise, "pairwise", ' ', TRUE, FALSE, error)) + return FALSE; + if (!ADD_STRING_LIST_VAL (self, setting, wireless_security, group, groups, "group", ' ', TRUE, FALSE, error)) + return FALSE; } /* WEP keys if required */ @@ -685,25 +720,22 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, const char *wep1 = nm_setting_wireless_security_get_wep_key (setting, 1); const char *wep2 = nm_setting_wireless_security_get_wep_key (setting, 2); const char *wep3 = nm_setting_wireless_security_get_wep_key (setting, 3); - char *value; - if (!add_wep_key (self, wep0, "wep_key0", wep_type)) + if (!add_wep_key (self, wep0, "wep_key0", wep_type, error)) return FALSE; - if (!add_wep_key (self, wep1, "wep_key1", wep_type)) + if (!add_wep_key (self, wep1, "wep_key1", wep_type, error)) return FALSE; - if (!add_wep_key (self, wep2, "wep_key2", wep_type)) + if (!add_wep_key (self, wep2, "wep_key2", wep_type, error)) return FALSE; - if (!add_wep_key (self, wep3, "wep_key3", wep_type)) + if (!add_wep_key (self, wep3, "wep_key3", wep_type, error)) return FALSE; if (wep0 || wep1 || wep2 || wep3) { + gs_free char *value = NULL; + value = g_strdup_printf ("%d", nm_setting_wireless_security_get_wep_tx_keyidx (setting)); - success = nm_supplicant_config_add_option (self, "wep_tx_keyidx", value, -1, FALSE); - g_free (value); - if (!success) { - nm_log_warn (LOGD_SUPPLICANT, "Error adding wep_tx_keyidx to supplicant config."); + if (!nm_supplicant_config_add_option (self, "wep_tx_keyidx", value, -1, FALSE, error)) return FALSE; - } } } @@ -713,24 +745,29 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, const char *tmp; tmp = nm_setting_wireless_security_get_leap_username (setting); - if (!add_string_val (self, tmp, "identity", FALSE, FALSE)) + if (!add_string_val (self, tmp, "identity", FALSE, FALSE, error)) return FALSE; tmp = nm_setting_wireless_security_get_leap_password (setting); - if (!add_string_val (self, tmp, "password", FALSE, TRUE)) + if (!add_string_val (self, tmp, "password", FALSE, TRUE, error)) return FALSE; - if (!add_string_val (self, "leap", "eap", TRUE, FALSE)) + if (!add_string_val (self, "leap", "eap", TRUE, FALSE, error)) return FALSE; } else { + g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "Invalid key-mgmt \"%s\" for leap", key_mgmt); return FALSE; } } else { /* 802.1x for Dynamic WEP and WPA-Enterprise */ if (!strcmp (key_mgmt, "ieee8021x") || !strcmp (key_mgmt, "wpa-eap")) { - if (!setting_8021x) - return FALSE; - if (!nm_supplicant_config_add_setting_8021x (self, setting_8021x, con_uuid, mtu, FALSE)) + if (!setting_8021x) { + g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "Cannot set key-mgmt %s with missing 8021x setting", key_mgmt); + return FALSE; + } + if (!nm_supplicant_config_add_setting_8021x (self, setting_8021x, con_uuid, mtu, FALSE, error)) return FALSE; } @@ -738,14 +775,14 @@ nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, /* If using WPA Enterprise, enable optimized background scanning * to ensure roaming within an ESS works well. */ - if (!nm_supplicant_config_add_option (self, "bgscan", "simple:30:-65:300", -1, FALSE)) - nm_log_warn (LOGD_SUPPLICANT, "Error enabling background scanning for ESS roaming"); + if (!nm_supplicant_config_add_option (self, "bgscan", "simple:30:-65:300", -1, FALSE, error)) + return FALSE; /* When using WPA-Enterprise, we want to use Proactive Key Caching (also * called Opportunistic Key Caching) to avoid full EAP exchanges when * roaming between access points in the same mobility group. */ - if (!nm_supplicant_config_add_option (self, "proactive_key_caching", "1", -1, FALSE)) + if (!nm_supplicant_config_add_option (self, "proactive_key_caching", "1", -1, FALSE, error)) return FALSE; } } @@ -758,12 +795,13 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, NMSetting8021x *setting, const char *con_uuid, guint32 mtu, - gboolean wired) + gboolean wired, + GError **error) { NMSupplicantConfigPrivate *priv; char *tmp; const char *peapver, *value, *path; - gboolean success, added; + gboolean added; GString *phase1, *phase2; GBytes *bytes; gboolean fast = FALSE; @@ -771,7 +809,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, gboolean fast_provisoning_allowed = FALSE; const char *ca_path_override = NULL, *ca_cert_override = NULL; guint32 frag, hdrs; - char *frag_str = NULL; + gs_free char *frag_str = NULL; g_return_val_if_fail (NM_IS_SUPPLICANT_CONFIG (self), FALSE); g_return_val_if_fail (setting != NULL, FALSE); @@ -781,36 +819,35 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, value = nm_setting_802_1x_get_password (setting); if (value) { - if (!add_string_val (self, value, "password", FALSE, TRUE)) + if (!add_string_val (self, value, "password", FALSE, TRUE, error)) return FALSE; } else { bytes = nm_setting_802_1x_get_password_raw (setting); if (bytes) { - success = nm_supplicant_config_add_option (self, - "password", - (const char *) g_bytes_get_data (bytes, NULL), - g_bytes_get_size (bytes), - TRUE); - if (!success) { - nm_log_warn (LOGD_SUPPLICANT, "Error adding password-raw to supplicant config."); + if (!nm_supplicant_config_add_option (self, + "password", + (const char *) g_bytes_get_data (bytes, NULL), + g_bytes_get_size (bytes), + TRUE, + error)) return FALSE; - } } } value = nm_setting_802_1x_get_pin (setting); - if (!add_string_val (self, value, "pin", FALSE, TRUE)) + if (!add_string_val (self, value, "pin", FALSE, TRUE, error)) return FALSE; if (wired) { - if (!add_string_val (self, "IEEE8021X", "key_mgmt", FALSE, FALSE)) + if (!add_string_val (self, "IEEE8021X", "key_mgmt", FALSE, FALSE, error)) return FALSE; /* Wired 802.1x must always use eapol_flags=0 */ - if (!add_string_val (self, "0", "eapol_flags", FALSE, FALSE)) + if (!add_string_val (self, "0", "eapol_flags", FALSE, FALSE, error)) return FALSE; - nm_supplicant_config_set_ap_scan (self, 0); + priv->ap_scan = 0; } - ADD_STRING_LIST_VAL (setting, 802_1x, eap_method, eap_methods, "eap", ' ', TRUE, FALSE); + if (!ADD_STRING_LIST_VAL (self, setting, 802_1x, eap_method, eap_methods, "eap", ' ', TRUE, FALSE, error)) + return FALSE; /* Check EAP method for special handling: PEAP + GTC, FAST */ num_eap = nm_setting_802_1x_get_num_eap_methods (setting); @@ -831,11 +868,8 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, frag = CLAMP (mtu - hdrs, 100, frag); frag_str = g_strdup_printf ("%u", frag); - if (!nm_supplicant_config_add_option (self, "fragment_size", frag_str, -1, FALSE)) { - g_free (frag_str); + if (!nm_supplicant_config_add_option (self, "fragment_size", frag_str, -1, FALSE, error)) return FALSE; - } - g_free (frag_str); phase1 = g_string_new (NULL); peapver = nm_setting_802_1x_get_phase1_peapver (setting); @@ -857,13 +891,13 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, if (phase1->len) g_string_append_c (phase1, ' '); g_string_append_printf (phase1, "fast_provisioning=%s", value); - + if (strcmp (value, "0") != 0) fast_provisoning_allowed = TRUE; } if (phase1->len) { - if (!add_string_val (self, phase1->str, "phase1", FALSE, FALSE)) { + if (!add_string_val (self, phase1->str, "phase1", FALSE, FALSE, error)) { g_string_free (phase1, TRUE); return FALSE; } @@ -886,7 +920,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, } if (phase2->len) { - if (!add_string_val (self, phase2->str, "phase2", FALSE, FALSE)) { + if (!add_string_val (self, phase2->str, "phase2", FALSE, FALSE, error)) { g_string_free (phase2, TRUE); return FALSE; } @@ -896,24 +930,24 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, /* PAC file */ path = nm_setting_802_1x_get_pac_file (setting); if (path) { - if (!add_string_val (self, path, "pac_file", FALSE, FALSE)) + if (!add_string_val (self, path, "pac_file", FALSE, FALSE, error)) return FALSE; } else { /* PAC file is not specified. * If provisioning is allowed, use an blob format. */ if (fast_provisoning_allowed) { - char *blob_name = g_strdup_printf ("blob://pac-blob-%s", con_uuid); - if (!add_string_val (self, blob_name, "pac_file", FALSE, FALSE)) { - g_free (blob_name); + gs_free char *blob_name = NULL; + + blob_name = g_strdup_printf ("blob://pac-blob-%s", con_uuid); + if (!add_string_val (self, blob_name, "pac_file", FALSE, FALSE, error)) return FALSE; - } - g_free (blob_name); } else { /* This is only error for EAP-FAST; don't disturb other methods. */ if (fast) { - nm_log_err (LOGD_SUPPLICANT, "EAP-FAST error: no PAC file provided and " - "automatic PAC provisioning is disabled."); + g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "EAP-FAST error: no PAC file provided and " + "automatic PAC provisioning is disabled"); return FALSE; } } @@ -932,7 +966,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, path = nm_setting_802_1x_get_ca_path (setting); path = ca_path_override ? ca_path_override : path; if (path) { - if (!add_string_val (self, path, "ca_path", FALSE, FALSE)) + if (!add_string_val (self, path, "ca_path", FALSE, FALSE, error)) return FALSE; } @@ -940,23 +974,24 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, path = nm_setting_802_1x_get_phase2_ca_path (setting); path = ca_path_override ? ca_path_override : path; if (path) { - if (!add_string_val (self, path, "ca_path2", FALSE, FALSE)) + if (!add_string_val (self, path, "ca_path2", FALSE, FALSE, error)) return FALSE; } /* CA certificate */ if (ca_cert_override) { - if (!add_string_val (self, ca_cert_override, "ca_cert", FALSE, FALSE)) + if (!add_string_val (self, ca_cert_override, "ca_cert", FALSE, FALSE, error)) return FALSE; } else { switch (nm_setting_802_1x_get_ca_cert_scheme (setting)) { case NM_SETTING_802_1X_CK_SCHEME_BLOB: bytes = nm_setting_802_1x_get_ca_cert_blob (setting); - ADD_BLOB_VAL (bytes, "ca_cert", con_uuid); + if (!nm_supplicant_config_add_blob_for_connection (self, bytes, "ca_cert", con_uuid, error)) + return FALSE; break; case NM_SETTING_802_1X_CK_SCHEME_PATH: path = nm_setting_802_1x_get_ca_cert_path (setting); - if (!add_string_val (self, path, "ca_cert", FALSE, FALSE)) + if (!add_string_val (self, path, "ca_cert", FALSE, FALSE, error)) return FALSE; break; default: @@ -966,17 +1001,18 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, /* Phase 2 CA certificate */ if (ca_cert_override) { - if (!add_string_val (self, ca_cert_override, "ca_cert2", FALSE, FALSE)) + if (!add_string_val (self, ca_cert_override, "ca_cert2", FALSE, FALSE, error)) return FALSE; } else { switch (nm_setting_802_1x_get_phase2_ca_cert_scheme (setting)) { case NM_SETTING_802_1X_CK_SCHEME_BLOB: bytes = nm_setting_802_1x_get_phase2_ca_cert_blob (setting); - ADD_BLOB_VAL (bytes, "ca_cert2", con_uuid); + if (!nm_supplicant_config_add_blob_for_connection (self, bytes, "ca_cert2", con_uuid, error)) + return FALSE; break; case NM_SETTING_802_1X_CK_SCHEME_PATH: path = nm_setting_802_1x_get_phase2_ca_cert_path (setting); - if (!add_string_val (self, path, "ca_cert2", FALSE, FALSE)) + if (!add_string_val (self, path, "ca_cert2", FALSE, FALSE, error)) return FALSE; break; default: @@ -986,27 +1022,30 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, /* Subject match */ value = nm_setting_802_1x_get_subject_match (setting); - if (!add_string_val (self, value, "subject_match", FALSE, FALSE)) + if (!add_string_val (self, value, "subject_match", FALSE, FALSE, error)) return FALSE; value = nm_setting_802_1x_get_phase2_subject_match (setting); - if (!add_string_val (self, value, "subject_match2", FALSE, FALSE)) + if (!add_string_val (self, value, "subject_match2", FALSE, FALSE, error)) return FALSE; /* altSubjectName match */ - ADD_STRING_LIST_VAL (setting, 802_1x, altsubject_match, altsubject_matches, "altsubject_match", ';', FALSE, FALSE); - ADD_STRING_LIST_VAL (setting, 802_1x, phase2_altsubject_match, phase2_altsubject_matches, "altsubject_match2", ';', FALSE, FALSE); + if (!ADD_STRING_LIST_VAL (self, setting, 802_1x, altsubject_match, altsubject_matches, "altsubject_match", ';', FALSE, FALSE, error)) + return FALSE; + if (!ADD_STRING_LIST_VAL (self, setting, 802_1x, phase2_altsubject_match, phase2_altsubject_matches, "altsubject_match2", ';', FALSE, FALSE, error)) + return FALSE; /* Private key */ added = FALSE; switch (nm_setting_802_1x_get_private_key_scheme (setting)) { case NM_SETTING_802_1X_CK_SCHEME_BLOB: bytes = nm_setting_802_1x_get_private_key_blob (setting); - ADD_BLOB_VAL (bytes, "private_key", con_uuid); + if (!nm_supplicant_config_add_blob_for_connection (self, bytes, "private_key", con_uuid, error)) + return FALSE; added = TRUE; break; case NM_SETTING_802_1X_CK_SCHEME_PATH: path = nm_setting_802_1x_get_private_key_path (setting); - if (!add_string_val (self, path, "private_key", FALSE, FALSE)) + if (!add_string_val (self, path, "private_key", FALSE, FALSE, error)) return FALSE; added = TRUE; break; @@ -1028,7 +1067,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, * isn't decrypted at all. */ value = nm_setting_802_1x_get_private_key_password (setting); - if (!add_string_val (self, value, "private_key_passwd", FALSE, TRUE)) + if (!add_string_val (self, value, "private_key_passwd", FALSE, TRUE, error)) return FALSE; } @@ -1039,11 +1078,12 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, switch (nm_setting_802_1x_get_client_cert_scheme (setting)) { case NM_SETTING_802_1X_CK_SCHEME_BLOB: bytes = nm_setting_802_1x_get_client_cert_blob (setting); - ADD_BLOB_VAL (bytes, "client_cert", con_uuid); + if (!nm_supplicant_config_add_blob_for_connection (self, bytes, "client_cert", con_uuid, error)) + return FALSE; break; case NM_SETTING_802_1X_CK_SCHEME_PATH: path = nm_setting_802_1x_get_client_cert_path (setting); - if (!add_string_val (self, path, "client_cert", FALSE, FALSE)) + if (!add_string_val (self, path, "client_cert", FALSE, FALSE, error)) return FALSE; break; default: @@ -1057,12 +1097,13 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, switch (nm_setting_802_1x_get_phase2_private_key_scheme (setting)) { case NM_SETTING_802_1X_CK_SCHEME_BLOB: bytes = nm_setting_802_1x_get_phase2_private_key_blob (setting); - ADD_BLOB_VAL (bytes, "private_key2", con_uuid); + if (!nm_supplicant_config_add_blob_for_connection (self, bytes, "private_key2", con_uuid, error)) + return FALSE; added = TRUE; break; case NM_SETTING_802_1X_CK_SCHEME_PATH: path = nm_setting_802_1x_get_phase2_private_key_path (setting); - if (!add_string_val (self, path, "private_key2", FALSE, FALSE)) + if (!add_string_val (self, path, "private_key2", FALSE, FALSE, error)) return FALSE; added = TRUE; break; @@ -1084,7 +1125,7 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, * isn't decrypted at all. */ value = nm_setting_802_1x_get_phase2_private_key_password (setting); - if (!add_string_val (self, value, "private_key2_passwd", FALSE, TRUE)) + if (!add_string_val (self, value, "private_key2_passwd", FALSE, TRUE, error)) return FALSE; } @@ -1095,11 +1136,12 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, switch (nm_setting_802_1x_get_phase2_client_cert_scheme (setting)) { case NM_SETTING_802_1X_CK_SCHEME_BLOB: bytes = nm_setting_802_1x_get_phase2_client_cert_blob (setting); - ADD_BLOB_VAL (bytes, "client_cert2", con_uuid); + if (!nm_supplicant_config_add_blob_for_connection (self, bytes, "client_cert2", con_uuid, error)) + return FALSE; break; case NM_SETTING_802_1X_CK_SCHEME_PATH: path = nm_setting_802_1x_get_phase2_client_cert_path (setting); - if (!add_string_val (self, path, "client_cert2", FALSE, FALSE)) + if (!add_string_val (self, path, "client_cert2", FALSE, FALSE, error)) return FALSE; break; default: @@ -1109,18 +1151,18 @@ nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, } value = nm_setting_802_1x_get_identity (setting); - if (!add_string_val (self, value, "identity", FALSE, FALSE)) + if (!add_string_val (self, value, "identity", FALSE, FALSE, error)) return FALSE; value = nm_setting_802_1x_get_anonymous_identity (setting); - if (!add_string_val (self, value, "anonymous_identity", FALSE, FALSE)) + if (!add_string_val (self, value, "anonymous_identity", FALSE, FALSE, error)) return FALSE; return TRUE; } gboolean -nm_supplicant_config_add_no_security (NMSupplicantConfig *self) +nm_supplicant_config_add_no_security (NMSupplicantConfig *self, GError **error) { - return nm_supplicant_config_add_option (self, "key_mgmt", "NONE", -1, FALSE); + return nm_supplicant_config_add_option (self, "key_mgmt", "NONE", -1, FALSE, error); } diff --git a/src/supplicant-manager/nm-supplicant-config.h b/src/supplicant-manager/nm-supplicant-config.h index 9708a6d3..921bc16c 100644 --- a/src/supplicant-manager/nm-supplicant-config.h +++ b/src/supplicant-manager/nm-supplicant-config.h @@ -22,10 +22,10 @@ #ifndef __NETWORKMANAGER_SUPPLICANT_CONFIG_H__ #define __NETWORKMANAGER_SUPPLICANT_CONFIG_H__ -#include #include #include #include +#include "nm-default.h" #include "nm-supplicant-types.h" G_BEGIN_DECLS @@ -54,8 +54,7 @@ NMSupplicantConfig *nm_supplicant_config_new (void); guint32 nm_supplicant_config_get_ap_scan (NMSupplicantConfig *self); -void nm_supplicant_config_set_ap_scan (NMSupplicantConfig *self, - guint32 ap_scan); +const char *nm_supplicant_config_get_mac_randomization (NMSupplicantConfig *self); gboolean nm_supplicant_config_fast_required (NMSupplicantConfig *self); @@ -65,21 +64,27 @@ GHashTable *nm_supplicant_config_get_blobs (NMSupplicantConfig *self); gboolean nm_supplicant_config_add_setting_wireless (NMSupplicantConfig *self, NMSettingWireless *setting, - guint32 fixed_freq); + guint32 fixed_freq, + NMSupplicantFeature mac_randomization_support, + NMSettingMacRandomization mac_randomization_fallback, + GError **error); gboolean nm_supplicant_config_add_setting_wireless_security (NMSupplicantConfig *self, NMSettingWirelessSecurity *setting, NMSetting8021x *setting_8021x, const char *con_uuid, - guint32 mtu); + guint32 mtu, + GError **error); -gboolean nm_supplicant_config_add_no_security (NMSupplicantConfig *self); +gboolean nm_supplicant_config_add_no_security (NMSupplicantConfig *self, + GError **error); gboolean nm_supplicant_config_add_setting_8021x (NMSupplicantConfig *self, NMSetting8021x *setting, const char *con_uuid, guint32 mtu, - gboolean wired); + gboolean wired, + GError **error); G_END_DECLS diff --git a/src/supplicant-manager/nm-supplicant-interface.c b/src/supplicant-manager/nm-supplicant-interface.c index 30be23ae..9251af1f 100644 --- a/src/supplicant-manager/nm-supplicant-interface.c +++ b/src/supplicant-manager/nm-supplicant-interface.c @@ -23,15 +23,13 @@ #include #include -#include +#include "nm-default.h" #include "NetworkManagerUtils.h" #include "nm-supplicant-interface.h" -#include "nm-logging.h" #include "nm-supplicant-config.h" -#include "nm-glib-compat.h" -#include "gsystem-local-alloc.h" #include "nm-core-internal.h" +#include "nm-dbus-compat.h" #define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interface" #define WPAS_DBUS_IFACE_BSS WPAS_DBUS_INTERFACE ".BSS" @@ -64,6 +62,7 @@ static guint signals[LAST_SIGNAL] = { 0 }; enum { PROP_0 = 0, PROP_SCANNING, + PROP_CURRENT_BSS, LAST_PROP }; @@ -72,7 +71,8 @@ typedef struct { char * dev; gboolean is_wireless; gboolean has_credreq; /* Whether querying 802.1x credentials is supported */ - ApSupport ap_support; /* Lightweight AP mode support */ + NMSupplicantFeature ap_support; /* Lightweight AP mode support */ + NMSupplicantFeature mac_randomization_support; gboolean fast_supported; guint32 max_scan_ssids; guint32 ready_count; @@ -91,6 +91,7 @@ typedef struct { char * net_path; guint32 blobs_left; GHashTable * bss_proxies; + char * current_bss; gint32 last_scan; /* timestamp as returned by nm_utils_get_monotonic_timestamp_s() */ @@ -333,6 +334,17 @@ nm_supplicant_interface_get_scanning (NMSupplicantInterface *self) return FALSE; } +const char * +nm_supplicant_interface_get_current_bss (NMSupplicantInterface *self) +{ + NMSupplicantInterfacePrivate *priv; + + g_return_val_if_fail (self != NULL, FALSE); + + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + return priv->state >= NM_SUPPLICANT_INTERFACE_STATE_READY ? priv->current_bss : NULL; +} + gint32 nm_supplicant_interface_get_last_scan_time (NMSupplicantInterface *self) { @@ -413,21 +425,10 @@ nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self, 5000, NULL, error); - /* reply will be unrefed when function exits */ - return !!reply; -} - -static gboolean -_dbus_error_has_name (GError *error, const char *dbus_error_name) -{ - gs_free char *error_name = NULL; - gboolean is_error = FALSE; + if (error && *error) + g_dbus_error_strip_remote_error (*error); - if (error && g_dbus_error_is_remote_error (error)) { - error_name = g_dbus_error_get_remote_error (error); - is_error = !g_strcmp0 (error_name, dbus_error_name); - } - return is_error; + return !!reply; } static void @@ -452,7 +453,7 @@ iface_check_netreply_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ self = NM_SUPPLICANT_INTERFACE (user_data); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - if (variant || _dbus_error_has_name (error, "fi.w1.wpa_supplicant1.InvalidArgs")) + if (variant || _nm_dbus_error_has_name (error, "fi.w1.wpa_supplicant1.InvalidArgs")) priv->has_credreq = TRUE; nm_log_dbg (LOGD_SUPPLICANT, "Supplicant %s network credentials requests", @@ -461,7 +462,7 @@ iface_check_netreply_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ iface_check_ready (self); } -ApSupport +NMSupplicantFeature nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self) { return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->ap_support; @@ -469,7 +470,7 @@ nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self) void nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self, - ApSupport ap_support) + NMSupplicantFeature ap_support) { NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); @@ -480,8 +481,31 @@ nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self, priv->ap_support = ap_support; } +NMSupplicantFeature +nm_supplicant_interface_get_mac_randomization_support (NMSupplicantInterface *self) +{ + return NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self)->mac_randomization_support; +} + +static void +set_preassoc_scan_mac_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +{ + gs_unref_variant GVariant *variant = NULL; + gs_free_error GError *error = NULL; + + variant = _nm_dbus_proxy_call_finish (proxy, result, + G_VARIANT_TYPE ("()"), + &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + if (error) + nm_log_warn (LOGD_SUPPLICANT, "Failed to enable scan MAC address randomization"); + + iface_check_ready (NM_SUPPLICANT_INTERFACE (user_data)); +} + static void -iface_check_ap_mode_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +iface_introspect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { NMSupplicantInterface *self; NMSupplicantInterfacePrivate *priv; @@ -489,77 +513,115 @@ iface_check_ap_mode_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_d gs_free_error GError *error = NULL; const char *data; - /* The ProbeRequest method only exists if AP mode has been enabled */ - variant = g_dbus_proxy_call_finish (proxy, result, &error); + variant = _nm_dbus_proxy_call_finish (proxy, result, + G_VARIANT_TYPE ("(s)"), + &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; self = NM_SUPPLICANT_INTERFACE (user_data); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE ("(s)"))) { + if (variant) { g_variant_get (variant, "(&s)", &data); + + /* The ProbeRequest method only exists if AP mode has been enabled */ if (strstr (data, "ProbeRequest")) - priv->ap_support = AP_SUPPORT_YES; + priv->ap_support = NM_SUPPLICANT_FEATURE_YES; + + if (strstr (data, "PreassocMacAddr")) { + priv->mac_randomization_support = NM_SUPPLICANT_FEATURE_YES; + + /* Turn on MAC randomization during scans by default */ + priv->ready_count++; + g_dbus_proxy_call (priv->iface_proxy, + DBUS_INTERFACE_PROPERTIES ".Set", + g_variant_new ("(ssv)", + WPAS_DBUS_IFACE_INTERFACE, + "PreassocMacAddr", + g_variant_new_string ("1")), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->init_cancellable, + (GAsyncReadyCallback) set_preassoc_scan_mac_cb, + self); + } } iface_check_ready (self); } -#define MATCH_SIGNAL(s, n, v, t) (!strcmp (s, n) && g_variant_is_of_type (v, t)) - static void -signal_cb (GDBusProxy *proxy, - const gchar *sender, - const gchar *signal, - GVariant *args, - gpointer user_data) +wpas_iface_scan_done (GDBusProxy *proxy, + gboolean success, + gpointer user_data) { NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - const char *path, *field, *message; - gboolean success; + GVariant *props; + GHashTableIter iter; + char *bss_path; + GDBusProxy *bss_proxy; - if (MATCH_SIGNAL (signal, "ScanDone", args, G_VARIANT_TYPE ("(b)"))) { - GVariant *props; - GHashTableIter iter; - char *bss_path; - GDBusProxy *bss_proxy; + /* Cache last scan completed time */ + priv->last_scan = nm_utils_get_monotonic_timestamp_s (); + + g_signal_emit (self, signals[SCAN_DONE], 0, success); + + /* Emit NEW_BSS so that wifi device has the APs (in case it removed them) */ + g_hash_table_iter_init (&iter, priv->bss_proxies); + while (g_hash_table_iter_next (&iter, (gpointer) &bss_path, (gpointer) &bss_proxy)) { + if (g_object_get_data (G_OBJECT (bss_proxy), BSS_PROXY_INITED)) { + props = _get_bss_proxy_properties (self, bss_proxy); + if (props) { + g_signal_emit (self, signals[NEW_BSS], 0, + bss_path, + g_variant_ref_sink (props)); + g_variant_unref (props); + } + } + } +} + +static void +wpas_iface_bss_added (GDBusProxy *proxy, + const char *path, + GVariant *props, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - /* Cache last scan completed time */ + if (priv->scanning) priv->last_scan = nm_utils_get_monotonic_timestamp_s (); - g_variant_get (args, "(b)", &success); - g_signal_emit (self, signals[SCAN_DONE], 0, success); - - /* Emit NEW_BSS so that wifi device has the APs (in case it removed them) */ - g_hash_table_iter_init (&iter, priv->bss_proxies); - while (g_hash_table_iter_next (&iter, (gpointer) &bss_path, (gpointer) &bss_proxy)) { - if (g_object_get_data (G_OBJECT (bss_proxy), BSS_PROXY_INITED)) { - props = _get_bss_proxy_properties (self, bss_proxy); - if (props) { - g_signal_emit (self, signals[NEW_BSS], 0, - bss_path, - g_variant_ref_sink (props)); - g_variant_unref (props); - } - } - } - } else if (MATCH_SIGNAL (signal, "BSSAdded", args, G_VARIANT_TYPE ("(oa{sv})"))) { - if (priv->scanning) - priv->last_scan = nm_utils_get_monotonic_timestamp_s (); + handle_new_bss (self, path); +} - g_variant_get (args, "(&oa{sv})", &path, NULL); - handle_new_bss (self, path); - } else if (MATCH_SIGNAL (signal, "BSSRemoved", args, G_VARIANT_TYPE ("(o)"))) { - g_variant_get (args, "(&o)", &path); - g_signal_emit (self, signals[BSS_REMOVED], 0, path); - g_hash_table_remove (priv->bss_proxies, path); - } else if (MATCH_SIGNAL (signal, "NetworkRequest", args, G_VARIANT_TYPE ("(oss)"))) { - g_variant_get (args, "(&o&s&s)", &path, &field, &message); - if (priv->has_credreq && priv->net_path && !g_strcmp0 (path, priv->net_path)) - g_signal_emit (self, signals[CREDENTIALS_REQUEST], 0, field, message); - } +static void +wpas_iface_bss_removed (GDBusProxy *proxy, + const char *path, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + g_signal_emit (self, signals[BSS_REMOVED], 0, path); + g_hash_table_remove (priv->bss_proxies, path); +} + +static void +wpas_iface_network_request (GDBusProxy *proxy, + const char *path, + const char *field, + const char *message, + gpointer user_data) +{ + NMSupplicantInterface *self = NM_SUPPLICANT_INTERFACE (user_data); + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + if (priv->has_credreq && priv->net_path && !g_strcmp0 (path, priv->net_path)) + g_signal_emit (self, signals[CREDENTIALS_REQUEST], 0, field, message); } static void @@ -575,6 +637,8 @@ props_changed_cb (GDBusProxy *proxy, gint32 i32; GVariant *v; + g_object_freeze_notify (G_OBJECT (self)); + if (g_variant_lookup (changed_properties, "Scanning", "b", &b)) set_scanning (self, b); @@ -595,6 +659,16 @@ props_changed_cb (GDBusProxy *proxy, g_free (array); } + if (g_variant_lookup (changed_properties, "CurrentBSS", "&o", &s)) { + if (strcmp (s, "/") == 0) + s = NULL; + if (g_strcmp0 (s, priv->current_bss) != 0) { + g_free (priv->current_bss); + priv->current_bss = g_strdup (s); + g_object_notify (G_OBJECT (self), NM_SUPPLICANT_INTERFACE_CURRENT_BSS); + } + } + v = g_variant_lookup_value (changed_properties, "Capabilities", G_VARIANT_TYPE_VARDICT); if (v) { parse_capabilities (self, v); @@ -614,6 +688,8 @@ props_changed_cb (GDBusProxy *proxy, priv->disconnect_reason); } } + + g_object_thaw_notify (G_OBJECT (self)); } static void @@ -634,7 +710,38 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ self = NM_SUPPLICANT_INTERFACE (user_data); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - g_signal_connect (priv->iface_proxy, "g-signal", G_CALLBACK (signal_cb), self); + _nm_dbus_signal_connect (priv->iface_proxy, "ScanDone", G_VARIANT_TYPE ("(b)"), + G_CALLBACK (wpas_iface_scan_done), self); + _nm_dbus_signal_connect (priv->iface_proxy, "BSSAdded", G_VARIANT_TYPE ("(oa{sv})"), + G_CALLBACK (wpas_iface_bss_added), self); + _nm_dbus_signal_connect (priv->iface_proxy, "BSSRemoved", G_VARIANT_TYPE ("(o)"), + G_CALLBACK (wpas_iface_bss_removed), self); + _nm_dbus_signal_connect (priv->iface_proxy, "NetworkRequest", G_VARIANT_TYPE ("(oss)"), + G_CALLBACK (wpas_iface_network_request), self); + + /* Scan result aging parameters */ + g_dbus_proxy_call (priv->iface_proxy, + "org.freedesktop.DBus.Properties.Set", + g_variant_new ("(ssv)", + WPAS_DBUS_IFACE_INTERFACE, + "BSSExpireAge", + g_variant_new_uint32 (250)), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->init_cancellable, + NULL, + NULL); + g_dbus_proxy_call (priv->iface_proxy, + "org.freedesktop.DBus.Properties.Set", + g_variant_new ("(ssv)", + WPAS_DBUS_IFACE_INTERFACE, + "BSSExpireCount", + g_variant_new_uint32 (2)), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->init_cancellable, + NULL, + NULL); /* Check whether NetworkReply and AP mode are supported */ priv->ready_count = 1; @@ -650,7 +757,8 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ (GAsyncReadyCallback) iface_check_netreply_cb, self); - if (priv->ap_support == AP_SUPPORT_UNKNOWN) { + if (priv->ap_support == NM_SUPPLICANT_FEATURE_UNKNOWN || + priv->mac_randomization_support == NM_SUPPLICANT_FEATURE_UNKNOWN) { /* If the global supplicant capabilities property is not present, we can * fall back to checking whether the ProbeRequest method is supported. If * neither of these works we have no way of determining if AP mode is @@ -658,12 +766,12 @@ on_iface_proxy_acquired (GDBusProxy *proxy, GAsyncResult *result, gpointer user_ */ priv->ready_count++; g_dbus_proxy_call (priv->iface_proxy, - "org.freedesktop.DBus.Introspectable.Introspect", + DBUS_INTERFACE_INTROSPECTABLE ".Introspect", NULL, G_DBUS_CALL_FLAGS_NONE, -1, priv->init_cancellable, - (GAsyncReadyCallback) iface_check_ap_mode_cb, + (GAsyncReadyCallback) iface_introspect_cb, self); } } @@ -698,20 +806,22 @@ interface_get_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) NMSupplicantInterfacePrivate *priv; gs_unref_variant GVariant *variant = NULL; gs_free_error GError *error = NULL; - char *path; + const char *path; - variant = g_dbus_proxy_call_finish (proxy, result, &error); + variant = _nm_dbus_proxy_call_finish (proxy, result, + G_VARIANT_TYPE ("(o)"), + &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; self = NM_SUPPLICANT_INTERFACE (user_data); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE ("(o)"))) { - g_variant_get (variant, "(o)", &path); + if (variant) { + g_variant_get (variant, "(&o)", &path); interface_add_done (self, path); - g_free (path); } else { + g_dbus_error_strip_remote_error (error); nm_log_err (LOGD_SUPPLICANT, "(%s): error getting interface: %s", priv->dev, error->message); set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN); } @@ -724,20 +834,21 @@ interface_add_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) NMSupplicantInterfacePrivate *priv; gs_free_error GError *error = NULL; gs_unref_variant GVariant *variant = NULL; - char *path; + const char *path; - variant = g_dbus_proxy_call_finish (proxy, result, &error); + variant = _nm_dbus_proxy_call_finish (proxy, result, + G_VARIANT_TYPE ("(o)"), + &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; self = NM_SUPPLICANT_INTERFACE (user_data); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE ("(o)"))) { - g_variant_get (variant, "(o)", &path); + if (variant) { + g_variant_get (variant, "(&o)", &path); interface_add_done (self, path); - g_free (path); - } else if (_dbus_error_has_name (error, WPAS_ERROR_EXISTS_ERROR)) { + } else if (_nm_dbus_error_has_name (error, WPAS_ERROR_EXISTS_ERROR)) { /* Interface already added, just get its object path */ g_dbus_proxy_call (priv->wpas_proxy, "GetInterface", @@ -759,10 +870,12 @@ interface_add_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) * activation. Wait for it to start by moving back to the INIT * state. */ + g_dbus_error_strip_remote_error (error); nm_log_dbg (LOGD_SUPPLICANT, "(%s): failed to activate supplicant: %s", priv->dev, error->message); set_state (self, NM_SUPPLICANT_INTERFACE_STATE_INIT); } else { + g_dbus_error_strip_remote_error (error); nm_log_err (LOGD_SUPPLICANT, "(%s): error adding interface: %s", priv->dev, error->message); set_state (self, NM_SUPPLICANT_INTERFACE_STATE_DOWN); } @@ -877,8 +990,12 @@ log_result_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) gs_free_error GError *error = NULL; reply = g_dbus_proxy_call_finish (proxy, result, &error); - if (!reply && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - nm_log_warn (LOGD_SUPPLICANT, "Failed to %s: %s.", error->message, (char *) user_data); + if ( !reply + && !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) + && !strstr (error->message, "fi.w1.wpa_supplicant1.NotConnected")) { + g_dbus_error_strip_remote_error (error); + nm_log_warn (LOGD_SUPPLICANT, "Failed to %s: %s.", (char *) user_data, error->message); + } } void @@ -936,6 +1053,7 @@ select_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) reply = g_dbus_proxy_call_finish (proxy, result, &err); if (!reply && !g_error_matches (err, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + g_dbus_error_strip_remote_error (err); nm_log_warn (LOGD_SUPPLICANT, "Couldn't select network config: %s.", err->message); emit_error_helper (NM_SUPPLICANT_INTERFACE (user_data), err); } @@ -978,6 +1096,7 @@ add_blob_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) if (reply) call_select_network (self); else { + g_dbus_error_strip_remote_error (err); nm_log_warn (LOGD_SUPPLICANT, "Couldn't set network certificates: %s.", err->message); emit_error_helper (self, err); } @@ -995,30 +1114,26 @@ add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) const char *blob_name; GByteArray *blob_data; - reply = g_dbus_proxy_call_finish (proxy, result, &error); + reply = _nm_dbus_proxy_call_finish (proxy, result, + G_VARIANT_TYPE ("(o)"), + &error); if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; self = NM_SUPPLICANT_INTERFACE (user_data); priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); - if (reply && !g_variant_is_of_type (reply, G_VARIANT_TYPE ("(o)"))) { - error = g_error_new (NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "Unexpected AddNetwork reply type %s", - g_variant_get_type_string (reply)); - } - g_free (priv->net_path); priv->net_path = NULL; if (error) { + g_dbus_error_strip_remote_error (error); nm_log_warn (LOGD_SUPPLICANT, "Adding network to supplicant failed: %s.", error->message); emit_error_helper (self, error); return; } g_variant_get (reply, "(o)", &priv->net_path); - g_assert (priv->net_path); /* Send blobs first; otherwise jump to selecting the network */ blobs = nm_supplicant_config_get_blobs (priv->cfg); @@ -1042,6 +1157,51 @@ add_network_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) call_select_network (self); } +static void +add_network (NMSupplicantInterface *self) +{ + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + g_dbus_proxy_call (priv->iface_proxy, + "AddNetwork", + g_variant_new ("(@a{sv})", nm_supplicant_config_to_variant (priv->cfg)), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->assoc_cancellable, + (GAsyncReadyCallback) add_network_cb, + self); +} + +static void +set_mac_randomization_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) +{ + NMSupplicantInterface *self; + NMSupplicantInterfacePrivate *priv; + gs_unref_variant GVariant *reply = NULL; + gs_free_error GError *error = NULL; + + reply = g_dbus_proxy_call_finish (proxy, result, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_SUPPLICANT_INTERFACE (user_data); + priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); + + if (!reply) { + g_dbus_error_strip_remote_error (error); + nm_log_warn (LOGD_SUPPLICANT, "Couldn't send MAC randomization mode to " + "the supplicant interface: %s.", + error->message); + emit_error_helper (self, error); + return; + } + + nm_log_info (LOGD_SUPPLICANT, "Config: set MAC randomization to %s", + nm_supplicant_config_get_mac_randomization (priv->cfg)); + + add_network (self); +} + static void set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { @@ -1058,6 +1218,7 @@ set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (self); if (!reply) { + g_dbus_error_strip_remote_error (error); nm_log_warn (LOGD_SUPPLICANT, "Couldn't send AP scan mode to the supplicant interface: %s.", error->message); emit_error_helper (self, error); @@ -1067,19 +1228,30 @@ set_ap_scan_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) nm_log_info (LOGD_SUPPLICANT, "Config: set interface ap_scan to %d", nm_supplicant_config_get_ap_scan (priv->cfg)); - g_dbus_proxy_call (priv->iface_proxy, - "AddNetwork", - g_variant_new ("(@a{sv})", nm_supplicant_config_to_variant (priv->cfg)), - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->assoc_cancellable, - (GAsyncReadyCallback) add_network_cb, - self); + if (priv->mac_randomization_support == NM_SUPPLICANT_FEATURE_YES) { + const char *mac_randomization = nm_supplicant_config_get_mac_randomization (priv->cfg); + + /* Enable/disable association MAC address randomization */ + g_dbus_proxy_call (priv->iface_proxy, + DBUS_INTERFACE_PROPERTIES ".Set", + g_variant_new ("(ssv)", + WPAS_DBUS_IFACE_INTERFACE, + "MacAddr", + g_variant_new_string (mac_randomization)), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->assoc_cancellable, + (GAsyncReadyCallback) set_mac_randomization_cb, + self); + } else { + add_network (self); + } } gboolean nm_supplicant_interface_set_config (NMSupplicantInterface *self, - NMSupplicantConfig *cfg) + NMSupplicantConfig *cfg, + GError **error) { NMSupplicantInterfacePrivate *priv; @@ -1093,7 +1265,8 @@ nm_supplicant_interface_set_config (NMSupplicantInterface *self, * it an EAP-FAST configuration. */ if (nm_supplicant_config_fast_required (cfg) && !priv->fast_supported) { - nm_log_warn (LOGD_SUPPLICANT, "EAP-FAST is not supported by the supplicant"); + g_set_error (error, NM_SUPPLICANT_ERROR, NM_SUPPLICANT_ERROR_CONFIG, + "EAP-FAST is not supported by the supplicant"); return FALSE; } @@ -1101,7 +1274,7 @@ nm_supplicant_interface_set_config (NMSupplicantInterface *self, if (cfg) { priv->cfg = g_object_ref (cfg); g_dbus_proxy_call (priv->iface_proxy, - "org.freedesktop.DBus.Properties.Set", + DBUS_INTERFACE_PROPERTIES ".Set", g_variant_new ("(ssv)", WPAS_DBUS_IFACE_INTERFACE, "ApScan", @@ -1258,7 +1431,7 @@ NMSupplicantInterface * nm_supplicant_interface_new (const char *ifname, gboolean is_wireless, gboolean fast_supported, - ApSupport ap_support, + NMSupplicantFeature ap_support, gboolean start_now) { NMSupplicantInterface *self; @@ -1295,11 +1468,7 @@ set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } static void @@ -1308,9 +1477,14 @@ get_property (GObject *object, GValue *value, GParamSpec *pspec) { + NMSupplicantInterfacePrivate *priv = NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object); + switch (prop_id) { case PROP_SCANNING: - g_value_set_boolean (value, NM_SUPPLICANT_INTERFACE_GET_PRIVATE (object)->scanning); + g_value_set_boolean (value, priv->scanning); + break; + case PROP_CURRENT_BSS: + g_value_set_string (value, priv->current_bss); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1341,6 +1515,7 @@ dispose (GObject *object) g_clear_pointer (&priv->net_path, g_free); g_clear_pointer (&priv->dev, g_free); g_clear_pointer (&priv->object_path, g_free); + g_clear_pointer (&priv->current_bss, g_free); g_clear_object (&priv->cfg); @@ -1367,6 +1542,13 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property + (object_class, PROP_CURRENT_BSS, + g_param_spec_string (NM_SUPPLICANT_INTERFACE_CURRENT_BSS, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + /* Signals */ signals[STATE] = g_signal_new (NM_SUPPLICANT_INTERFACE_STATE, @@ -1398,7 +1580,7 @@ nm_supplicant_interface_class_init (NMSupplicantInterfaceClass *klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NMSupplicantInterfaceClass, bss_updated), NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER); + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_VARIANT); signals[BSS_REMOVED] = g_signal_new (NM_SUPPLICANT_INTERFACE_BSS_REMOVED, diff --git a/src/supplicant-manager/nm-supplicant-interface.h b/src/supplicant-manager/nm-supplicant-interface.h index 1b1139d4..2f866076 100644 --- a/src/supplicant-manager/nm-supplicant-interface.h +++ b/src/supplicant-manager/nm-supplicant-interface.h @@ -22,7 +22,7 @@ #ifndef __NETWORKMANAGER_SUPPLICANT_INTERFACE_H__ #define __NETWORKMANAGER_SUPPLICANT_INTERFACE_H__ -#include +#include "nm-default.h" #include "nm-supplicant-types.h" /* @@ -54,6 +54,10 @@ enum { #define NM_IS_SUPPLICANT_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SUPPLICANT_INTERFACE)) #define NM_SUPPLICANT_INTERFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SUPPLICANT_INTERFACE, NMSupplicantInterfaceClass)) +/* Properties */ +#define NM_SUPPLICANT_INTERFACE_CURRENT_BSS "current-bss" + +/* Signals */ #define NM_SUPPLICANT_INTERFACE_STATE "state" #define NM_SUPPLICANT_INTERFACE_REMOVED "removed" #define NM_SUPPLICANT_INTERFACE_NEW_BSS "new-bss" @@ -63,12 +67,6 @@ enum { #define NM_SUPPLICANT_INTERFACE_CONNECTION_ERROR "connection-error" #define NM_SUPPLICANT_INTERFACE_CREDENTIALS_REQUEST "credentials-request" -typedef enum { - AP_SUPPORT_UNKNOWN = 0, /* Can't detect whether supported or not */ - AP_SUPPORT_NO = 1, /* AP mode definitely not supported */ - AP_SUPPORT_YES = 2, /* AP mode definitely supported */ -} ApSupport; - struct _NMSupplicantInterface { GObject parent; }; @@ -90,12 +88,12 @@ typedef struct { /* interface saw a new BSS */ void (*new_bss) (NMSupplicantInterface *iface, const char *object_path, - GHashTable *props); + GVariant *props); /* a BSS property changed */ void (*bss_updated) (NMSupplicantInterface *iface, const char *object_path, - GHashTable *props); + GVariant *props); /* supplicant removed a BSS from its scan list */ void (*bss_removed) (NMSupplicantInterface *iface, @@ -116,20 +114,20 @@ typedef struct { const char *message); } NMSupplicantInterfaceClass; - GType nm_supplicant_interface_get_type (void); NMSupplicantInterface * nm_supplicant_interface_new (const char *ifname, gboolean is_wireless, gboolean fast_supported, - ApSupport ap_support, + NMSupplicantFeature ap_support, gboolean start_now); void nm_supplicant_interface_set_supplicant_available (NMSupplicantInterface *self, gboolean available); gboolean nm_supplicant_interface_set_config (NMSupplicantInterface * iface, - NMSupplicantConfig * cfg); + NMSupplicantConfig * cfg, + GError **error); void nm_supplicant_interface_disconnect (NMSupplicantInterface * iface); @@ -145,6 +143,8 @@ const char *nm_supplicant_interface_state_to_string (guint32 state); gboolean nm_supplicant_interface_get_scanning (NMSupplicantInterface *self); +const char *nm_supplicant_interface_get_current_bss (NMSupplicantInterface *self); + gint32 nm_supplicant_interface_get_last_scan_time (NMSupplicantInterface *self); const char *nm_supplicant_interface_get_ifname (NMSupplicantInterface *self); @@ -158,9 +158,11 @@ gboolean nm_supplicant_interface_credentials_reply (NMSupplicantInterface *self, const char *value, GError **error); -ApSupport nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self); +NMSupplicantFeature nm_supplicant_interface_get_ap_support (NMSupplicantInterface *self); void nm_supplicant_interface_set_ap_support (NMSupplicantInterface *self, - ApSupport apmode); + NMSupplicantFeature apmode); + +NMSupplicantFeature nm_supplicant_interface_get_mac_randomization_support (NMSupplicantInterface *self); #endif /* NM_SUPPLICANT_INTERFACE_H */ diff --git a/src/supplicant-manager/nm-supplicant-manager.c b/src/supplicant-manager/nm-supplicant-manager.c index 083f2ebc..29c0cd42 100644 --- a/src/supplicant-manager/nm-supplicant-manager.c +++ b/src/supplicant-manager/nm-supplicant-manager.c @@ -22,14 +22,11 @@ #include "config.h" #include -#include -#include - -#include "nm-glib-compat.h" +#include "nm-default.h" #include "nm-supplicant-manager.h" #include "nm-supplicant-interface.h" -#include "nm-logging.h" +#include "nm-supplicant-types.h" #include "nm-core-internal.h" #define NM_SUPPLICANT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ @@ -43,15 +40,19 @@ typedef struct { GCancellable * cancellable; gboolean running; - GHashTable * ifaces; - gboolean fast_supported; - ApSupport ap_support; - guint die_count_reset_id; - guint die_count; + GHashTable * ifaces; + gboolean fast_supported; + NMSupplicantFeature ap_support; + guint die_count_reset_id; + guint die_count; } NMSupplicantManagerPrivate; /********************************************************************/ +G_DEFINE_QUARK (nm-supplicant-error-quark, nm_supplicant_error); + +/********************************************************************/ + static inline gboolean die_count_exceeded (guint32 count) { @@ -150,15 +151,15 @@ update_capabilities (NMSupplicantManager *self) * * dbus: Add global capabilities property */ - priv->ap_support = AP_SUPPORT_UNKNOWN; + priv->ap_support = NM_SUPPLICANT_FEATURE_UNKNOWN; value = g_dbus_proxy_get_cached_property (priv->proxy, "Capabilities"); if (value) { if (g_variant_is_of_type (value, G_VARIANT_TYPE_STRING_ARRAY)) { array = g_variant_get_strv (value, NULL); - priv->ap_support = AP_SUPPORT_NO; + priv->ap_support = NM_SUPPLICANT_FEATURE_NO; if (_nm_utils_string_in_list ("ap", array)) - priv->ap_support = AP_SUPPORT_YES; + priv->ap_support = NM_SUPPLICANT_FEATURE_YES; g_free (array); } g_variant_unref (value); @@ -170,8 +171,8 @@ update_capabilities (NMSupplicantManager *self) nm_supplicant_interface_set_ap_support (iface, priv->ap_support); nm_log_dbg (LOGD_SUPPLICANT, "AP mode is %ssupported", - (priv->ap_support == AP_SUPPORT_YES) ? "" : - (priv->ap_support == AP_SUPPORT_NO) ? "not " : "possibly "); + (priv->ap_support == NM_SUPPLICANT_FEATURE_YES) ? "" : + (priv->ap_support == NM_SUPPLICANT_FEATURE_NO) ? "not " : "possibly "); /* EAP-FAST */ priv->fast_supported = FALSE; @@ -344,10 +345,7 @@ dispose (GObject *object) { NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (object); - if (priv->die_count_reset_id) { - g_source_remove (priv->die_count_reset_id); - priv->die_count_reset_id = 0; - } + nm_clear_g_source (&priv->die_count_reset_id); if (priv->cancellable) { g_cancellable_cancel (priv->cancellable); diff --git a/src/supplicant-manager/nm-supplicant-manager.h b/src/supplicant-manager/nm-supplicant-manager.h index 3b8fddf4..d7456467 100644 --- a/src/supplicant-manager/nm-supplicant-manager.h +++ b/src/supplicant-manager/nm-supplicant-manager.h @@ -22,7 +22,7 @@ #ifndef __NETWORKMANAGER_SUPPLICANT_MANAGER_H__ #define __NETWORKMANAGER_SUPPLICANT_MANAGER_H__ -#include +#include "nm-default.h" #include "nm-supplicant-types.h" #include "nm-device.h" diff --git a/src/supplicant-manager/nm-supplicant-settings-verify.c b/src/supplicant-manager/nm-supplicant-settings-verify.c index 1328fd51..f2d56540 100644 --- a/src/supplicant-manager/nm-supplicant-settings-verify.c +++ b/src/supplicant-manager/nm-supplicant-settings-verify.c @@ -20,12 +20,12 @@ #include "config.h" -#include #include #include #include #include +#include "nm-default.h" #include "nm-supplicant-settings-verify.h" struct Opt { diff --git a/src/supplicant-manager/nm-supplicant-types.h b/src/supplicant-manager/nm-supplicant-types.h index 1c16e494..e9be5be4 100644 --- a/src/supplicant-manager/nm-supplicant-types.h +++ b/src/supplicant-manager/nm-supplicant-types.h @@ -29,4 +29,24 @@ typedef struct _NMSupplicantManager NMSupplicantManager; typedef struct _NMSupplicantInterface NMSupplicantInterface; typedef struct _NMSupplicantConfig NMSupplicantConfig; +typedef enum { + NM_SUPPLICANT_FEATURE_UNKNOWN = 0, /* Can't detect whether supported or not */ + NM_SUPPLICANT_FEATURE_NO = 1, /* Feature definitely not supported */ + NM_SUPPLICANT_FEATURE_YES = 2, /* Feature definitely supported */ +} NMSupplicantFeature; + +/** + * NMSupplicantError: + * @NM_SUPPLICANT_ERROR_UNKNOWN: unknown or unclassified error + * @NM_SUPPLICANT_ERROR_CONFIG: a failure constructing the + * wpa-supplicant configuration. + */ +typedef enum { + NM_SUPPLICANT_ERROR_UNKNOWN = 0, /*< nick=Unknown >*/ + NM_SUPPLICANT_ERROR_CONFIG = 1, /*< nick=Config >*/ +} NMSupplicantError; + +#define NM_SUPPLICANT_ERROR (nm_supplicant_error_quark ()) +GQuark nm_supplicant_error_quark (void); + #endif /* NM_SUPPLICANT_TYPES_H */ diff --git a/src/supplicant-manager/tests/Makefile.am b/src/supplicant-manager/tests/Makefile.am index 517f57b7..9ac0387c 100644 --- a/src/supplicant-manager/tests/Makefile.am +++ b/src/supplicant-manager/tests/Makefile.am @@ -1,18 +1,17 @@ SUBDIRS=certs AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/supplicant-manager \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ -DTEST_CERT_DIR=\"$(srcdir)/certs/\" \ - $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) + $(GLIB_CFLAGS) noinst_PROGRAMS = test-supplicant-config diff --git a/src/supplicant-manager/tests/Makefile.in b/src/supplicant-manager/tests/Makefile.in index e36c4c00..cbc8a5a1 100644 --- a/src/supplicant-manager/tests/Makefile.in +++ b/src/supplicant-manager/tests/Makefile.in @@ -444,7 +444,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -456,8 +455,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -467,6 +464,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -521,16 +519,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -567,6 +562,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -595,7 +592,6 @@ 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@ @@ -610,6 +606,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -670,6 +668,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -677,6 +676,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -694,18 +694,17 @@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ SUBDIRS = certs AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/supplicant-manager \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ -DTEST_CERT_DIR=\"$(srcdir)/certs/\" \ - $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) + $(GLIB_CFLAGS) test_supplicant_config_SOURCES = \ test-supplicant-config.c diff --git a/src/supplicant-manager/tests/certs/Makefile.in b/src/supplicant-manager/tests/certs/Makefile.in index fcfdd689..7f29bb3c 100644 --- a/src/supplicant-manager/tests/certs/Makefile.in +++ b/src/supplicant-manager/tests/certs/Makefile.in @@ -146,7 +146,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -158,8 +157,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -169,6 +166,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -223,16 +221,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -269,6 +264,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -297,7 +294,6 @@ 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@ @@ -312,6 +308,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -372,6 +370,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -379,6 +378,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ diff --git a/src/supplicant-manager/tests/test-supplicant-config.c b/src/supplicant-manager/tests/test-supplicant-config.c index 15be2ba8..bd532b24 100644 --- a/src/supplicant-manager/tests/test-supplicant-config.c +++ b/src/supplicant-manager/tests/test-supplicant-config.c @@ -30,12 +30,11 @@ #include #include -#include - #include "nm-core-internal.h" #include "nm-supplicant-config.h" #include "nm-supplicant-settings-verify.h" +#include "nm-default.h" #include "nm-test-utils.h" @@ -159,12 +158,19 @@ test_wifi_open (void) "*added 'bssid' value '11:22:33:44:55:66'*"); g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*added 'freq_list' value *"); - g_assert (nm_supplicant_config_add_setting_wireless (config, s_wifi, 0)); + g_assert (nm_supplicant_config_add_setting_wireless (config, + s_wifi, + 0, + NM_SUPPLICANT_FEATURE_UNKNOWN, + NM_SETTING_MAC_RANDOMIZATION_DEFAULT, + &error)); + g_assert_no_error (error); g_test_assert_expected_messages (); g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*added 'key_mgmt' value 'NONE'"); - g_assert (nm_supplicant_config_add_no_security (config)); + g_assert (nm_supplicant_config_add_no_security (config, &error)); + g_assert_no_error (error); g_test_assert_expected_messages (); config_dict = nm_supplicant_config_to_variant (config); @@ -257,7 +263,13 @@ test_wifi_wep_key (const char *detail, "*added 'bssid' value '11:22:33:44:55:66'*"); g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*added 'freq_list' value *"); - g_assert (nm_supplicant_config_add_setting_wireless (config, s_wifi, 0)); + g_assert (nm_supplicant_config_add_setting_wireless (config, + s_wifi, + 0, + NM_SUPPLICANT_FEATURE_UNKNOWN, + NM_SETTING_MAC_RANDOMIZATION_DEFAULT, + &error)); + g_assert_no_error (error); g_test_assert_expected_messages (); g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, @@ -270,7 +282,9 @@ test_wifi_wep_key (const char *detail, s_wsec, NULL, "376aced7-b28c-46be-9a62-fcdf072571da", - 1500)); + 1500, + &error)); + g_assert_no_error (error); g_test_assert_expected_messages (); config_dict = nm_supplicant_config_to_variant (config); @@ -394,7 +408,13 @@ test_wifi_wpa_psk (const char *detail, "*added 'bssid' value '11:22:33:44:55:66'*"); g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*added 'freq_list' value *"); - g_assert (nm_supplicant_config_add_setting_wireless (config, s_wifi, 0)); + g_assert (nm_supplicant_config_add_setting_wireless (config, + s_wifi, + 0, + NM_SUPPLICANT_FEATURE_UNKNOWN, + NM_SETTING_MAC_RANDOMIZATION_DEFAULT, + &error)); + g_assert_no_error (error); g_test_assert_expected_messages (); g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, @@ -411,7 +431,9 @@ test_wifi_wpa_psk (const char *detail, s_wsec, NULL, "376aced7-b28c-46be-9a62-fcdf072571da", - 1500)); + 1500, + &error)); + g_assert_no_error (error); g_test_assert_expected_messages (); config_dict = nm_supplicant_config_to_variant (config); @@ -533,7 +555,13 @@ test_wifi_eap (void) "*added 'bssid' value '11:22:33:44:55:66'*"); g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*added 'freq_list' value *"); - g_assert (nm_supplicant_config_add_setting_wireless (config, s_wifi, 0)); + g_assert (nm_supplicant_config_add_setting_wireless (config, + s_wifi, + 0, + NM_SUPPLICANT_FEATURE_UNKNOWN, + NM_SETTING_MAC_RANDOMIZATION_DEFAULT, + &error)); + g_assert_no_error (error); g_test_assert_expected_messages (); g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, @@ -560,7 +588,9 @@ test_wifi_eap (void) s_wsec, s_8021x, "d5b488af-9cab-41ed-bad4-97709c58430f", - mtu)); + mtu, + &error)); + g_assert_no_error (error); g_test_assert_expected_messages (); config_dict = nm_supplicant_config_to_variant (config); @@ -581,7 +611,7 @@ NMTST_DEFINE (); int main (int argc, char **argv) { - nmtst_init (&argc, &argv, TRUE); + nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); g_test_add_func ("/supplicant-config/wifi-open", test_wifi_open); g_test_add_func ("/supplicant-config/wifi-wep", test_wifi_wep); diff --git a/src/systemd/nm-sd-adapt.c b/src/systemd/nm-sd-adapt.c new file mode 100644 index 00000000..8b29aed5 --- /dev/null +++ b/src/systemd/nm-sd-adapt.c @@ -0,0 +1,237 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* 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) 2014 Red Hat, Inc. + */ + +#include "config.h" + +#include +#include +#include + +#include "sd-event.h" +#include "fd-util.h" +#include "time-util.h" + +struct sd_event_source { + guint refcount; + guint id; + gpointer user_data; + + GIOChannel *channel; + + union { + struct { + sd_event_io_handler_t cb; + } io; + struct { + sd_event_time_handler_t cb; + uint64_t usec; + } time; + }; +}; + +static struct sd_event_source * +source_new (void) +{ + struct sd_event_source *source; + + source = g_slice_new0 (struct sd_event_source); + source->refcount = 1; + return source; +} + +int +sd_event_source_set_priority (sd_event_source *s, int64_t priority) +{ + return 0; +} + +sd_event_source* +sd_event_source_unref (sd_event_source *s) +{ + + if (!s) + return NULL; + + g_return_val_if_fail (s->refcount, NULL); + + s->refcount--; + if (s->refcount == 0) { + if (s->id) + g_source_remove (s->id); + if (s->channel) { + /* Don't shut down the channel since systemd will soon close + * the file descriptor itself, which would cause -EBADF. + */ + g_io_channel_unref (s->channel); + } + g_slice_free (struct sd_event_source, s); + } + return NULL; +} + +int +sd_event_source_set_description(sd_event_source *s, const char *description) +{ + if (!s) + return -EINVAL; + + g_source_set_name_by_id (s->id, description); + return 0; +} + +static gboolean +io_ready (GIOChannel *channel, GIOCondition condition, struct sd_event_source *source) +{ + int r, revents = 0; + gboolean result; + + if (condition & G_IO_IN) + revents |= EPOLLIN; + if (condition & G_IO_OUT) + revents |= EPOLLOUT; + if (condition & G_IO_PRI) + revents |= EPOLLPRI; + if (condition & G_IO_ERR) + revents |= EPOLLERR; + if (condition & G_IO_HUP) + revents |= EPOLLHUP; + + source->refcount++; + + r = source->io.cb (source, g_io_channel_unix_get_fd (channel), revents, source->user_data); + if (r < 0 || source->refcount <= 1) { + source->id = 0; + result = G_SOURCE_REMOVE; + } else + result = G_SOURCE_CONTINUE; + + sd_event_source_unref (source); + + return result; +} + +int +sd_event_add_io (sd_event *e, sd_event_source **s, int fd, uint32_t events, sd_event_io_handler_t callback, void *userdata) +{ + struct sd_event_source *source; + GIOChannel *channel; + GIOCondition condition = 0; + + /* systemd supports floating sd_event_source by omitting the @s argument. + * We don't have such users and don't implement floating references. */ + g_return_val_if_fail (s, -EINVAL); + + channel = g_io_channel_unix_new (fd); + if (!channel) + return -EINVAL; + + source = source_new (); + source->io.cb = callback; + source->user_data = userdata; + source->channel = channel; + + if (events & EPOLLIN) + condition |= G_IO_IN; + if (events & EPOLLOUT) + condition |= G_IO_OUT; + if (events & EPOLLPRI) + condition |= G_IO_PRI; + if (events & EPOLLERR) + condition |= G_IO_ERR; + if (events & EPOLLHUP) + condition |= G_IO_HUP; + + g_io_channel_set_encoding (source->channel, NULL, NULL); + g_io_channel_set_buffered (source->channel, FALSE); + source->id = g_io_add_watch (source->channel, condition, (GIOFunc) io_ready, source); + + *s = source; + return 0; +} + +static gboolean +time_ready (struct sd_event_source *source) +{ + source->refcount++; + + source->time.cb (source, source->time.usec, source->user_data); + source->id = 0; + + sd_event_source_unref (source); + + return G_SOURCE_REMOVE; +} + +int +sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata) +{ + struct sd_event_source *source; + uint64_t n = now (clock); + + /* systemd supports floating sd_event_source by omitting the @s argument. + * We don't have such users and don't implement floating references. */ + g_return_val_if_fail (s, -EINVAL); + + source = source_new (); + source->time.cb = callback; + source->user_data = userdata; + source->time.usec = usec; + + if (usec > 1000) + usec = n < usec - 1000 ? usec - n : 1000; + source->id = g_timeout_add (usec / 1000, (GSourceFunc) time_ready, source); + + *s = source; + return 0; +} + +/* sd_event is basically a GMainContext; but since we only + * ever use the default context, nothing to do here. + */ + +int +sd_event_default (sd_event **e) +{ + *e = GUINT_TO_POINTER (1); + return 0; +} + +sd_event* +sd_event_ref (sd_event *e) +{ + return e; +} + +sd_event* +sd_event_unref (sd_event *e) +{ + return NULL; +} + +int +sd_event_now (sd_event *e, clockid_t clock, uint64_t *usec) +{ + *usec = now (clock); + return 0; +} + +int asynchronous_close(int fd) { + safe_close(fd); + return -1; +} + diff --git a/src/systemd/nm-sd-adapt.h b/src/systemd/nm-sd-adapt.h new file mode 100644 index 00000000..967cb48f --- /dev/null +++ b/src/systemd/nm-sd-adapt.h @@ -0,0 +1,152 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* 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) 2014 - 2015 Red Hat, Inc. + */ + +#ifndef NM_SD_ADAPT_H +#define NM_SD_ADAPT_H + +#include "config.h" + +#include +#include +#include +#include + +#include "nm-default.h" + +#define noreturn G_GNUC_NORETURN + +#ifndef CLOCK_BOOTTIME +#define CLOCK_BOOTTIME 7 +#endif + +/*****************************************************************************/ + +static inline NMLogLevel +_slog_level_to_nm (int slevel) +{ + switch (slevel) { + case LOG_DEBUG: return LOGL_DEBUG; + case LOG_WARNING: return LOGL_WARN; + case LOG_CRIT: + case LOG_ERR: return LOGL_ERR; + case LOG_INFO: + case LOG_NOTICE: + default: return LOGL_INFO; + } +} + +#define log_internal(level, error, file, line, func, format, ...) \ +({ \ + const int _nm_e = (error); \ + const NMLogLevel _nm_l = _slog_level_to_nm ((level)); \ + \ + if (nm_logging_enabled (_nm_l, LOGD_DHCP)) { \ + const char *_nm_location = strrchr ((""file), '/'); \ + \ + _nm_log_impl (_nm_location ? _nm_location + 1 : (""file), (line), (func), _nm_l, LOGD_DHCP, _nm_e, ("%s"format), "libsystemd: ", ## __VA_ARGS__); \ + } \ + (_nm_e > 0 ? -_nm_e : _nm_e); \ +}) + +#define log_full_errno(level, error, ...) \ +({ \ + log_internal(level, error, __FILE__, __LINE__, __func__, __VA_ARGS__); \ +}) + +#define log_assert_failed(text, file, line, func) \ +G_STMT_START { \ + log_internal (LOG_CRIT, 0, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.", text, file, line, func); \ + g_assert_not_reached (); \ +} G_STMT_END + +#define log_assert_failed_unreachable(text, file, line, func) \ +G_STMT_START { \ + log_internal (LOG_CRIT, 0, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.", text, file, line, func); \ + g_assert_not_reached (); \ +} G_STMT_END + +#define log_assert_failed_return(text, file, line, func) \ +({ \ + log_internal (LOG_DEBUG, 0, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring.", text, file, line, func); \ + g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, text); \ + (void) 0; \ +}) + +/***************************************************************************** + * The remainder of the header is only enabled when building the systemd code + * itself. + *****************************************************************************/ + +#if (NETWORKMANAGER_COMPILATION) == NM_NETWORKMANAGER_COMPILATION_SYSTEMD + +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_AUXV_H +#include +#endif +#include +#include + +#include + +/* Missing in Linux 3.2.0, in Ubuntu 12.04 */ +#ifndef BPF_XOR +#define BPF_XOR 0xa0 +#endif + +/*****************************************************************************/ + +/* Can't include both net/if.h and linux/if.h; so have to define this here */ +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif + +#ifndef MAX_HANDLE_SZ +#define MAX_HANDLE_SZ 128 +#endif + + +/* + * Some toolchains (E.G. uClibc 0.9.33 and earlier) don't export + * CLOCK_BOOTTIME even though the kernel supports it, so provide a + * local definition + */ +#ifndef CLOCK_BOOTTIME +#define CLOCK_BOOTTIME 7 +#endif + +#include "sd-id128.h" +#include "sparse-endian.h" +#include "async.h" +#include "util.h" + +static inline pid_t gettid(void) { + return (pid_t) syscall(SYS_gettid); +} + +static inline bool is_main_thread(void) { + return TRUE; +} + +#endif /* (NETWORKMANAGER_COMPILATION) == NM_NETWORKMANAGER_COMPILATION_SYSTEMD */ + +#endif /* NM_SD_ADAPT_H */ + diff --git a/src/systemd/src/basic/alloc-util.c b/src/systemd/src/basic/alloc-util.c new file mode 100644 index 00000000..a849e139 --- /dev/null +++ b/src/systemd/src/basic/alloc-util.c @@ -0,0 +1,87 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +#include "alloc-util.h" +#include "macro.h" +#include "util.h" + +void* memdup(const void *p, size_t l) { + void *r; + + assert(p); + + r = malloc(l); + if (!r) + return NULL; + + memcpy(r, p, l); + return r; +} + +void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) { + size_t a, newalloc; + void *q; + + assert(p); + assert(allocated); + + if (*allocated >= need) + return *p; + + newalloc = MAX(need * 2, 64u / size); + a = newalloc * size; + + /* check for overflows */ + if (a < size * need) + return NULL; + + q = realloc(*p, a); + if (!q) + return NULL; + + *p = q; + *allocated = newalloc; + return q; +} + +void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) { + size_t prev; + uint8_t *q; + + assert(p); + assert(allocated); + + prev = *allocated; + + q = greedy_realloc(p, allocated, need, size); + if (!q) + return NULL; + + if (*allocated > prev) + memzero(q + prev * size, (*allocated - prev) * size); + + return q; +} diff --git a/src/systemd/src/basic/alloc-util.h b/src/systemd/src/basic/alloc-util.h new file mode 100644 index 00000000..f9be5e85 --- /dev/null +++ b/src/systemd/src/basic/alloc-util.h @@ -0,0 +1,111 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "macro.h" + +#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n))) + +#define new0(t, n) ((t*) calloc((n), sizeof(t))) + +#define newa(t, n) ((t*) alloca(sizeof(t)*(n))) + +#define newa0(t, n) ((t*) alloca0(sizeof(t)*(n))) + +#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) + +#define malloc0(n) (calloc(1, (n))) + +static inline void *mfree(void *memory) { + free(memory); + return NULL; +} + +void* memdup(const void *p, size_t l) _alloc_(2); + +static inline void freep(void *p) { + free(*(void**) p); +} + +#define _cleanup_free_ _cleanup_(freep) + +_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t a, size_t b) { + if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) + return NULL; + + return malloc(a * b); +} + +_alloc_(2, 3) static inline void *realloc_multiply(void *p, size_t a, size_t b) { + if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) + return NULL; + + return realloc(p, a * b); +} + +_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t a, size_t b) { + if (_unlikely_(b != 0 && a > ((size_t) -1) / b)) + return NULL; + + return memdup(p, a * b); +} + +void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size); +void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); + +#define GREEDY_REALLOC(array, allocated, need) \ + greedy_realloc((void**) &(array), &(allocated), (need), sizeof((array)[0])) + +#define GREEDY_REALLOC0(array, allocated, need) \ + greedy_realloc0((void**) &(array), &(allocated), (need), sizeof((array)[0])) + +#define alloca0(n) \ + ({ \ + char *_new_; \ + size_t _len_ = n; \ + _new_ = alloca(_len_); \ + (void *) memset(_new_, 0, _len_); \ + }) + +/* It's not clear what alignment glibc/gcc alloca() guarantee, hence provide a guaranteed safe version */ +#define alloca_align(size, align) \ + ({ \ + void *_ptr_; \ + size_t _mask_ = (align) - 1; \ + _ptr_ = alloca((size) + _mask_); \ + (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ + }) + +#define alloca0_align(size, align) \ + ({ \ + void *_new_; \ + size_t _size_ = (size); \ + _new_ = alloca_align(_size_, (align)); \ + (void*)memset(_new_, 0, _size_); \ + }) diff --git a/src/systemd/src/basic/async.h b/src/systemd/src/basic/async.h new file mode 100644 index 00000000..44b886a6 --- /dev/null +++ b/src/systemd/src/basic/async.h @@ -0,0 +1,29 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +int asynchronous_job(void* (*func)(void *p), void *arg); + +int asynchronous_sync(void); +int asynchronous_close(int fd); diff --git a/src/systemd/src/basic/escape.c b/src/systemd/src/basic/escape.c new file mode 100644 index 00000000..fe1737e5 --- /dev/null +++ b/src/systemd/src/basic/escape.c @@ -0,0 +1,493 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include + +#include "alloc-util.h" +#include "escape.h" +#include "hexdecoct.h" +#include "macro.h" +#include "utf8.h" + +size_t cescape_char(char c, char *buf) { + char * buf_old = buf; + + switch (c) { + + case '\a': + *(buf++) = '\\'; + *(buf++) = 'a'; + break; + case '\b': + *(buf++) = '\\'; + *(buf++) = 'b'; + break; + case '\f': + *(buf++) = '\\'; + *(buf++) = 'f'; + break; + case '\n': + *(buf++) = '\\'; + *(buf++) = 'n'; + break; + case '\r': + *(buf++) = '\\'; + *(buf++) = 'r'; + break; + case '\t': + *(buf++) = '\\'; + *(buf++) = 't'; + break; + case '\v': + *(buf++) = '\\'; + *(buf++) = 'v'; + break; + case '\\': + *(buf++) = '\\'; + *(buf++) = '\\'; + break; + case '"': + *(buf++) = '\\'; + *(buf++) = '"'; + break; + case '\'': + *(buf++) = '\\'; + *(buf++) = '\''; + break; + + default: + /* For special chars we prefer octal over + * hexadecimal encoding, simply because glib's + * g_strescape() does the same */ + if ((c < ' ') || (c >= 127)) { + *(buf++) = '\\'; + *(buf++) = octchar((unsigned char) c >> 6); + *(buf++) = octchar((unsigned char) c >> 3); + *(buf++) = octchar((unsigned char) c); + } else + *(buf++) = c; + break; + } + + return buf - buf_old; +} + +char *cescape_length(const char *s, size_t n) { + const char *f; + char *r, *t; + + assert(s || n == 0); + + /* Does C style string escaping. May be reversed with + * cunescape(). */ + + r = new(char, n*4 + 1); + if (!r) + return NULL; + + for (f = s, t = r; f < s + n; f++) + t += cescape_char(*f, t); + + *t = 0; + + return r; +} + +char *cescape(const char *s) { + assert(s); + + return cescape_length(s, strlen(s)); +} + +int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) { + int r = 1; + + assert(p); + assert(*p); + assert(ret); + + /* Unescapes C style. Returns the unescaped character in ret, + * unless we encountered a \u sequence in which case the full + * unicode character is returned in ret_unicode, instead. */ + + if (length != (size_t) -1 && length < 1) + return -EINVAL; + + switch (p[0]) { + + case 'a': + *ret = '\a'; + break; + case 'b': + *ret = '\b'; + break; + case 'f': + *ret = '\f'; + break; + case 'n': + *ret = '\n'; + break; + case 'r': + *ret = '\r'; + break; + case 't': + *ret = '\t'; + break; + case 'v': + *ret = '\v'; + break; + case '\\': + *ret = '\\'; + break; + case '"': + *ret = '"'; + break; + case '\'': + *ret = '\''; + break; + + case 's': + /* This is an extension of the XDG syntax files */ + *ret = ' '; + break; + + case 'x': { + /* hexadecimal encoding */ + int a, b; + + if (length != (size_t) -1 && length < 3) + return -EINVAL; + + a = unhexchar(p[1]); + if (a < 0) + return -EINVAL; + + b = unhexchar(p[2]); + if (b < 0) + return -EINVAL; + + /* Don't allow NUL bytes */ + if (a == 0 && b == 0) + return -EINVAL; + + *ret = (char) ((a << 4U) | b); + r = 3; + break; + } + + case 'u': { + /* C++11 style 16bit unicode */ + + int a[4]; + unsigned i; + uint32_t c; + + if (length != (size_t) -1 && length < 5) + return -EINVAL; + + for (i = 0; i < 4; i++) { + a[i] = unhexchar(p[1 + i]); + if (a[i] < 0) + return a[i]; + } + + c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3]; + + /* Don't allow 0 chars */ + if (c == 0) + return -EINVAL; + + if (c < 128) + *ret = c; + else { + if (!ret_unicode) + return -EINVAL; + + *ret = 0; + *ret_unicode = c; + } + + r = 5; + break; + } + + case 'U': { + /* C++11 style 32bit unicode */ + + int a[8]; + unsigned i; + uint32_t c; + + if (length != (size_t) -1 && length < 9) + return -EINVAL; + + for (i = 0; i < 8; i++) { + a[i] = unhexchar(p[1 + i]); + if (a[i] < 0) + return a[i]; + } + + c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) | + ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] << 8U) | ((uint32_t) a[6] << 4U) | (uint32_t) a[7]; + + /* Don't allow 0 chars */ + if (c == 0) + return -EINVAL; + + /* Don't allow invalid code points */ + if (!unichar_is_valid(c)) + return -EINVAL; + + if (c < 128) + *ret = c; + else { + if (!ret_unicode) + return -EINVAL; + + *ret = 0; + *ret_unicode = c; + } + + r = 9; + break; + } + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { + /* octal encoding */ + int a, b, c; + uint32_t m; + + if (length != (size_t) -1 && length < 3) + return -EINVAL; + + a = unoctchar(p[0]); + if (a < 0) + return -EINVAL; + + b = unoctchar(p[1]); + if (b < 0) + return -EINVAL; + + c = unoctchar(p[2]); + if (c < 0) + return -EINVAL; + + /* don't allow NUL bytes */ + if (a == 0 && b == 0 && c == 0) + return -EINVAL; + + /* Don't allow bytes above 255 */ + m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c; + if (m > 255) + return -EINVAL; + + *ret = m; + r = 3; + break; + } + + default: + return -EINVAL; + } + + return r; +} + +int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret) { + char *r, *t; + const char *f; + size_t pl; + + assert(s); + assert(ret); + + /* Undoes C style string escaping, and optionally prefixes it. */ + + pl = prefix ? strlen(prefix) : 0; + + r = new(char, pl+length+1); + if (!r) + return -ENOMEM; + + if (prefix) + memcpy(r, prefix, pl); + + for (f = s, t = r + pl; f < s + length; f++) { + size_t remaining; + uint32_t u; + char c; + int k; + + remaining = s + length - f; + assert(remaining > 0); + + if (*f != '\\') { + /* A literal literal, copy verbatim */ + *(t++) = *f; + continue; + } + + if (remaining == 1) { + if (flags & UNESCAPE_RELAX) { + /* A trailing backslash, copy verbatim */ + *(t++) = *f; + continue; + } + + free(r); + return -EINVAL; + } + + k = cunescape_one(f + 1, remaining - 1, &c, &u); + if (k < 0) { + if (flags & UNESCAPE_RELAX) { + /* Invalid escape code, let's take it literal then */ + *(t++) = '\\'; + continue; + } + + free(r); + return k; + } + + if (c != 0) + /* Non-Unicode? Let's encode this directly */ + *(t++) = c; + else + /* Unicode? Then let's encode this in UTF-8 */ + t += utf8_encode_unichar(t, u); + + f += k; + } + + *t = 0; + + *ret = r; + return t - r; +} + +int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret) { + return cunescape_length_with_prefix(s, length, NULL, flags, ret); +} + +int cunescape(const char *s, UnescapeFlags flags, char **ret) { + return cunescape_length(s, strlen(s), flags, ret); +} + +char *xescape(const char *s, const char *bad) { + char *r, *t; + const char *f; + + /* Escapes all chars in bad, in addition to \ and all special + * chars, in \xFF style escaping. May be reversed with + * cunescape(). */ + + r = new(char, strlen(s) * 4 + 1); + if (!r) + return NULL; + + for (f = s, t = r; *f; f++) { + + if ((*f < ' ') || (*f >= 127) || + (*f == '\\') || strchr(bad, *f)) { + *(t++) = '\\'; + *(t++) = 'x'; + *(t++) = hexchar(*f >> 4); + *(t++) = hexchar(*f); + } else + *(t++) = *f; + } + + *t = 0; + + return r; +} + +static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) { + assert(bad); + + for (; *s; s++) { + if (*s == '\\' || strchr(bad, *s)) + *(t++) = '\\'; + + *(t++) = *s; + } + + return t; +} + +char *shell_escape(const char *s, const char *bad) { + char *r, *t; + + r = new(char, strlen(s)*2+1); + if (!r) + return NULL; + + t = strcpy_backslash_escaped(r, s, bad); + *t = 0; + + return r; +} + +char *shell_maybe_quote(const char *s) { + const char *p; + char *r, *t; + + assert(s); + + /* Encloses a string in double quotes if necessary to make it + * OK as shell string. */ + + for (p = s; *p; p++) + if (*p <= ' ' || + *p >= 127 || + strchr(SHELL_NEED_QUOTES, *p)) + break; + + if (!*p) + return strdup(s); + + r = new(char, 1+strlen(s)*2+1+1); + if (!r) + return NULL; + + t = r; + *(t++) = '"'; + t = mempcpy(t, s, p - s); + + t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE); + + *(t++)= '"'; + *t = 0; + + return r; +} diff --git a/src/systemd/src/basic/escape.h b/src/systemd/src/basic/escape.h new file mode 100644 index 00000000..da8f7143 --- /dev/null +++ b/src/systemd/src/basic/escape.h @@ -0,0 +1,55 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "string-util.h" + +/* What characters are special in the shell? */ +/* must be escaped outside and inside double-quotes */ +#define SHELL_NEED_ESCAPE "\"\\`$" +/* can be escaped or double-quoted */ +#define SHELL_NEED_QUOTES SHELL_NEED_ESCAPE GLOB_CHARS "'()<>|&;" + +typedef enum UnescapeFlags { + UNESCAPE_RELAX = 1, +} UnescapeFlags; + +char *cescape(const char *s); +char *cescape_length(const char *s, size_t n); +size_t cescape_char(char c, char *buf); + +int cunescape(const char *s, UnescapeFlags flags, char **ret); +int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret); +int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret); +int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode); + +char *xescape(const char *s, const char *bad); + +char *shell_escape(const char *s, const char *bad); +char *shell_maybe_quote(const char *s); diff --git a/src/systemd/src/basic/fd-util.c b/src/systemd/src/basic/fd-util.c new file mode 100644 index 00000000..3828148c --- /dev/null +++ b/src/systemd/src/basic/fd-util.c @@ -0,0 +1,366 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include + +#include "fd-util.h" +#include "macro.h" +#if 0 /* NM_IGNORED */ +#include "missing.h" +#endif /* NM_IGNORED */ +#include "parse-util.h" +#include "path-util.h" +#include "socket-util.h" +#include "util.h" + +int close_nointr(int fd) { + assert(fd >= 0); + + if (close(fd) >= 0) + return 0; + + /* + * Just ignore EINTR; a retry loop is the wrong thing to do on + * Linux. + * + * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html + * https://bugzilla.gnome.org/show_bug.cgi?id=682819 + * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR + * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain + */ + if (errno == EINTR) + return 0; + + return -errno; +} + +int safe_close(int fd) { + + /* + * Like close_nointr() but cannot fail. Guarantees errno is + * unchanged. Is a NOP with negative fds passed, and returns + * -1, so that it can be used in this syntax: + * + * fd = safe_close(fd); + */ + + if (fd >= 0) { + PROTECT_ERRNO; + + /* The kernel might return pretty much any error code + * via close(), but the fd will be closed anyway. The + * only condition we want to check for here is whether + * the fd was invalid at all... */ + + assert_se(close_nointr(fd) != -EBADF); + } + + return -1; +} + +void safe_close_pair(int p[]) { + assert(p); + + if (p[0] == p[1]) { + /* Special case pairs which use the same fd in both + * directions... */ + p[0] = p[1] = safe_close(p[0]); + return; + } + + p[0] = safe_close(p[0]); + p[1] = safe_close(p[1]); +} + +void close_many(const int fds[], unsigned n_fd) { + unsigned i; + + assert(fds || n_fd <= 0); + + for (i = 0; i < n_fd; i++) + safe_close(fds[i]); +} + +int fclose_nointr(FILE *f) { + assert(f); + + /* Same as close_nointr(), but for fclose() */ + + if (fclose(f) == 0) + return 0; + + if (errno == EINTR) + return 0; + + return -errno; +} + +FILE* safe_fclose(FILE *f) { + + /* Same as safe_close(), but for fclose() */ + + if (f) { + PROTECT_ERRNO; + + assert_se(fclose_nointr(f) != EBADF); + } + + return NULL; +} + +DIR* safe_closedir(DIR *d) { + + if (d) { + PROTECT_ERRNO; + + assert_se(closedir(d) >= 0 || errno != EBADF); + } + + return NULL; +} + +int fd_nonblock(int fd, bool nonblock) { + int flags, nflags; + + assert(fd >= 0); + + flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) + return -errno; + + if (nonblock) + nflags = flags | O_NONBLOCK; + else + nflags = flags & ~O_NONBLOCK; + + if (nflags == flags) + return 0; + + if (fcntl(fd, F_SETFL, nflags) < 0) + return -errno; + + return 0; +} + +int fd_cloexec(int fd, bool cloexec) { + int flags, nflags; + + assert(fd >= 0); + + flags = fcntl(fd, F_GETFD, 0); + if (flags < 0) + return -errno; + + if (cloexec) + nflags = flags | FD_CLOEXEC; + else + nflags = flags & ~FD_CLOEXEC; + + if (nflags == flags) + return 0; + + if (fcntl(fd, F_SETFD, nflags) < 0) + return -errno; + + return 0; +} + +#if 0 /* NM_IGNORED */ +_pure_ static bool fd_in_set(int fd, const int fdset[], unsigned n_fdset) { + unsigned i; + + assert(n_fdset == 0 || fdset); + + for (i = 0; i < n_fdset; i++) + if (fdset[i] == fd) + return true; + + return false; +} + +int close_all_fds(const int except[], unsigned n_except) { + _cleanup_closedir_ DIR *d = NULL; + struct dirent *de; + int r = 0; + + assert(n_except == 0 || except); + + d = opendir("/proc/self/fd"); + if (!d) { + int fd; + struct rlimit rl; + + /* When /proc isn't available (for example in chroots) + * the fallback is brute forcing through the fd + * table */ + + assert_se(getrlimit(RLIMIT_NOFILE, &rl) >= 0); + for (fd = 3; fd < (int) rl.rlim_max; fd ++) { + + if (fd_in_set(fd, except, n_except)) + continue; + + if (close_nointr(fd) < 0) + if (errno != EBADF && r == 0) + r = -errno; + } + + return r; + } + + while ((de = readdir(d))) { + int fd = -1; + + if (hidden_file(de->d_name)) + continue; + + if (safe_atoi(de->d_name, &fd) < 0) + /* Let's better ignore this, just in case */ + continue; + + if (fd < 3) + continue; + + if (fd == dirfd(d)) + continue; + + if (fd_in_set(fd, except, n_except)) + continue; + + if (close_nointr(fd) < 0) { + /* Valgrind has its own FD and doesn't want to have it closed */ + if (errno != EBADF && r == 0) + r = -errno; + } + } + + return r; +} + +int same_fd(int a, int b) { + struct stat sta, stb; + pid_t pid; + int r, fa, fb; + + assert(a >= 0); + assert(b >= 0); + + /* Compares two file descriptors. Note that semantics are + * quite different depending on whether we have kcmp() or we + * don't. If we have kcmp() this will only return true for + * dup()ed file descriptors, but not otherwise. If we don't + * have kcmp() this will also return true for two fds of the same + * file, created by separate open() calls. Since we use this + * call mostly for filtering out duplicates in the fd store + * this difference hopefully doesn't matter too much. */ + + if (a == b) + return true; + + /* Try to use kcmp() if we have it. */ + pid = getpid(); + r = kcmp(pid, pid, KCMP_FILE, a, b); + if (r == 0) + return true; + if (r > 0) + return false; + if (errno != ENOSYS) + return -errno; + + /* We don't have kcmp(), use fstat() instead. */ + if (fstat(a, &sta) < 0) + return -errno; + + if (fstat(b, &stb) < 0) + return -errno; + + if ((sta.st_mode & S_IFMT) != (stb.st_mode & S_IFMT)) + return false; + + /* We consider all device fds different, since two device fds + * might refer to quite different device contexts even though + * they share the same inode and backing dev_t. */ + + if (S_ISCHR(sta.st_mode) || S_ISBLK(sta.st_mode)) + return false; + + if (sta.st_dev != stb.st_dev || sta.st_ino != stb.st_ino) + return false; + + /* The fds refer to the same inode on disk, let's also check + * if they have the same fd flags. This is useful to + * distinguish the read and write side of a pipe created with + * pipe(). */ + fa = fcntl(a, F_GETFL); + if (fa < 0) + return -errno; + + fb = fcntl(b, F_GETFL); + if (fb < 0) + return -errno; + + return fa == fb; +} +#endif /* NM_IGNORED */ + +void cmsg_close_all(struct msghdr *mh) { + struct cmsghdr *cmsg; + + assert(mh); + + CMSG_FOREACH(cmsg, mh) + if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) + close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); +} + +bool fdname_is_valid(const char *s) { + const char *p; + + /* Validates a name for $LISTEN_FDNAMES. We basically allow + * everything ASCII that's not a control character. Also, as + * special exception the ":" character is not allowed, as we + * use that as field separator in $LISTEN_FDNAMES. + * + * Note that the empty string is explicitly allowed + * here. However, we limit the length of the names to 255 + * characters. */ + + if (!s) + return false; + + for (p = s; *p; p++) { + if (*p < ' ') + return false; + if (*p >= 127) + return false; + if (*p == ':') + return false; + } + + return p - s < 256; +} diff --git a/src/systemd/src/basic/fd-util.h b/src/systemd/src/basic/fd-util.h new file mode 100644 index 00000000..3614dc78 --- /dev/null +++ b/src/systemd/src/basic/fd-util.h @@ -0,0 +1,77 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "macro.h" + +/* Make sure we can distinguish fd 0 and NULL */ +#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1) +#define PTR_TO_FD(p) (PTR_TO_INT(p)-1) + +int close_nointr(int fd); +int safe_close(int fd); +void safe_close_pair(int p[]); + +void close_many(const int fds[], unsigned n_fd); + +int fclose_nointr(FILE *f); +FILE* safe_fclose(FILE *f); +DIR* safe_closedir(DIR *f); + +static inline void closep(int *fd) { + safe_close(*fd); +} + +static inline void close_pairp(int (*p)[2]) { + safe_close_pair(*p); +} + +static inline void fclosep(FILE **f) { + safe_fclose(*f); +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); +DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); + +#define _cleanup_close_ _cleanup_(closep) +#define _cleanup_fclose_ _cleanup_(fclosep) +#define _cleanup_pclose_ _cleanup_(pclosep) +#define _cleanup_closedir_ _cleanup_(closedirp) +#define _cleanup_close_pair_ _cleanup_(close_pairp) + +int fd_nonblock(int fd, bool nonblock); +int fd_cloexec(int fd, bool cloexec); + +int close_all_fds(const int except[], unsigned n_except); + +int same_fd(int a, int b); + +void cmsg_close_all(struct msghdr *mh); + +bool fdname_is_valid(const char *s); diff --git a/src/systemd/src/basic/fileio.c b/src/systemd/src/basic/fileio.c new file mode 100644 index 00000000..913c6293 --- /dev/null +++ b/src/systemd/src/basic/fileio.c @@ -0,0 +1,1261 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alloc-util.h" +#include "ctype.h" +#include "escape.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hexdecoct.h" +#include "log.h" +#include "macro.h" +#include "parse-util.h" +#include "path-util.h" +#include "random-util.h" +#if 0 /* NM_IGNORED */ +#include "stdio-util.h" +#endif /* NM_IGNORED */ +#include "string-util.h" +#include "strv.h" +#include "time-util.h" +#include "umask-util.h" +#include "utf8.h" + +int write_string_stream(FILE *f, const char *line, bool enforce_newline) { + + assert(f); + assert(line); + + fputs(line, f); + if (enforce_newline && !endswith(line, "\n")) + fputc('\n', f); + + return fflush_and_check(f); +} + +static int write_string_file_atomic(const char *fn, const char *line, bool enforce_newline) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *p = NULL; + int r; + + assert(fn); + assert(line); + + r = fopen_temporary(fn, &f, &p); + if (r < 0) + return r; + + (void) fchmod_umask(fileno(f), 0644); + + r = write_string_stream(f, line, enforce_newline); + if (r >= 0) { + if (rename(p, fn) < 0) + r = -errno; + } + + if (r < 0) + (void) unlink(p); + + return r; +} + +int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags) { + _cleanup_fclose_ FILE *f = NULL; + int q, r; + + assert(fn); + assert(line); + + if (flags & WRITE_STRING_FILE_ATOMIC) { + assert(flags & WRITE_STRING_FILE_CREATE); + + r = write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE)); + if (r < 0) + goto fail; + + return r; + } + + if (flags & WRITE_STRING_FILE_CREATE) { + f = fopen(fn, "we"); + if (!f) { + r = -errno; + goto fail; + } + } else { + int fd; + + /* We manually build our own version of fopen(..., "we") that + * works without O_CREAT */ + fd = open(fn, O_WRONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) { + r = -errno; + goto fail; + } + + f = fdopen(fd, "we"); + if (!f) { + r = -errno; + safe_close(fd); + goto fail; + } + } + + r = write_string_stream(f, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE)); + if (r < 0) + goto fail; + + return 0; + +fail: + if (!(flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE)) + return r; + + f = safe_fclose(f); + + /* OK, the operation failed, but let's see if the right + * contents in place already. If so, eat up the error. */ + + q = verify_file(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE)); + if (q <= 0) + return r; + + return 0; +} + +int read_one_line_file(const char *fn, char **line) { + _cleanup_fclose_ FILE *f = NULL; + char t[LINE_MAX], *c; + + assert(fn); + assert(line); + + f = fopen(fn, "re"); + if (!f) + return -errno; + + if (!fgets(t, sizeof(t), f)) { + + if (ferror(f)) + return errno ? -errno : -EIO; + + t[0] = 0; + } + + c = strdup(t); + if (!c) + return -ENOMEM; + truncate_nl(c); + + *line = c; + return 0; +} + +int verify_file(const char *fn, const char *blob, bool accept_extra_nl) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *buf = NULL; + size_t l, k; + + assert(fn); + assert(blob); + + l = strlen(blob); + + if (accept_extra_nl && endswith(blob, "\n")) + accept_extra_nl = false; + + buf = malloc(l + accept_extra_nl + 1); + if (!buf) + return -ENOMEM; + + f = fopen(fn, "re"); + if (!f) + return -errno; + + /* We try to read one byte more than we need, so that we know whether we hit eof */ + errno = 0; + k = fread(buf, 1, l + accept_extra_nl + 1, f); + if (ferror(f)) + return errno > 0 ? -errno : -EIO; + + if (k != l && k != l + accept_extra_nl) + return 0; + if (memcmp(buf, blob, l) != 0) + return 0; + if (k > l && buf[l] != '\n') + return 0; + + return 1; +} + +int read_full_stream(FILE *f, char **contents, size_t *size) { + size_t n, l; + _cleanup_free_ char *buf = NULL; + struct stat st; + + assert(f); + assert(contents); + + if (fstat(fileno(f), &st) < 0) + return -errno; + + n = LINE_MAX; + + if (S_ISREG(st.st_mode)) { + + /* Safety check */ + if (st.st_size > 4*1024*1024) + return -E2BIG; + + /* Start with the right file size, but be prepared for + * files from /proc which generally report a file size + * of 0 */ + if (st.st_size > 0) + n = st.st_size; + } + + l = 0; + for (;;) { + char *t; + size_t k; + + t = realloc(buf, n+1); + if (!t) + return -ENOMEM; + + buf = t; + k = fread(buf + l, 1, n - l, f); + + if (k <= 0) { + if (ferror(f)) + return -errno; + + break; + } + + l += k; + n *= 2; + + /* Safety check */ + if (n > 4*1024*1024) + return -E2BIG; + } + + buf[l] = 0; + *contents = buf; + buf = NULL; /* do not free */ + + if (size) + *size = l; + + return 0; +} + +int read_full_file(const char *fn, char **contents, size_t *size) { + _cleanup_fclose_ FILE *f = NULL; + + assert(fn); + assert(contents); + + f = fopen(fn, "re"); + if (!f) + return -errno; + + return read_full_stream(f, contents, size); +} + +static int parse_env_file_internal( + FILE *f, + const char *fname, + const char *newline, + int (*push) (const char *filename, unsigned line, + const char *key, char *value, void *userdata, int *n_pushed), + void *userdata, + int *n_pushed) { + + _cleanup_free_ char *contents = NULL, *key = NULL; + size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1; + char *p, *value = NULL; + int r; + unsigned line = 1; + + enum { + PRE_KEY, + KEY, + PRE_VALUE, + VALUE, + VALUE_ESCAPE, + SINGLE_QUOTE_VALUE, + SINGLE_QUOTE_VALUE_ESCAPE, + DOUBLE_QUOTE_VALUE, + DOUBLE_QUOTE_VALUE_ESCAPE, + COMMENT, + COMMENT_ESCAPE + } state = PRE_KEY; + + assert(newline); + + if (f) + r = read_full_stream(f, &contents, NULL); + else + r = read_full_file(fname, &contents, NULL); + if (r < 0) + return r; + + for (p = contents; *p; p++) { + char c = *p; + + switch (state) { + + case PRE_KEY: + if (strchr(COMMENTS, c)) + state = COMMENT; + else if (!strchr(WHITESPACE, c)) { + state = KEY; + last_key_whitespace = (size_t) -1; + + if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { + r = -ENOMEM; + goto fail; + } + + key[n_key++] = c; + } + break; + + case KEY: + if (strchr(newline, c)) { + state = PRE_KEY; + line ++; + n_key = 0; + } else if (c == '=') { + state = PRE_VALUE; + last_value_whitespace = (size_t) -1; + } else { + if (!strchr(WHITESPACE, c)) + last_key_whitespace = (size_t) -1; + else if (last_key_whitespace == (size_t) -1) + last_key_whitespace = n_key; + + if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) { + r = -ENOMEM; + goto fail; + } + + key[n_key++] = c; + } + + break; + + case PRE_VALUE: + if (strchr(newline, c)) { + state = PRE_KEY; + line ++; + key[n_key] = 0; + + if (value) + value[n_value] = 0; + + /* strip trailing whitespace from key */ + if (last_key_whitespace != (size_t) -1) + key[last_key_whitespace] = 0; + + r = push(fname, line, key, value, userdata, n_pushed); + if (r < 0) + goto fail; + + n_key = 0; + value = NULL; + value_alloc = n_value = 0; + + } else if (c == '\'') + state = SINGLE_QUOTE_VALUE; + else if (c == '\"') + state = DOUBLE_QUOTE_VALUE; + else if (c == '\\') + state = VALUE_ESCAPE; + else if (!strchr(WHITESPACE, c)) { + state = VALUE; + + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } + + value[n_value++] = c; + } + + break; + + case VALUE: + if (strchr(newline, c)) { + state = PRE_KEY; + line ++; + + key[n_key] = 0; + + if (value) + value[n_value] = 0; + + /* Chomp off trailing whitespace from value */ + if (last_value_whitespace != (size_t) -1) + value[last_value_whitespace] = 0; + + /* strip trailing whitespace from key */ + if (last_key_whitespace != (size_t) -1) + key[last_key_whitespace] = 0; + + r = push(fname, line, key, value, userdata, n_pushed); + if (r < 0) + goto fail; + + n_key = 0; + value = NULL; + value_alloc = n_value = 0; + + } else if (c == '\\') { + state = VALUE_ESCAPE; + last_value_whitespace = (size_t) -1; + } else { + if (!strchr(WHITESPACE, c)) + last_value_whitespace = (size_t) -1; + else if (last_value_whitespace == (size_t) -1) + last_value_whitespace = n_value; + + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } + + value[n_value++] = c; + } + + break; + + case VALUE_ESCAPE: + state = VALUE; + + if (!strchr(newline, c)) { + /* Escaped newlines we eat up entirely */ + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } + + value[n_value++] = c; + } + break; + + case SINGLE_QUOTE_VALUE: + if (c == '\'') + state = PRE_VALUE; + else if (c == '\\') + state = SINGLE_QUOTE_VALUE_ESCAPE; + else { + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } + + value[n_value++] = c; + } + + break; + + case SINGLE_QUOTE_VALUE_ESCAPE: + state = SINGLE_QUOTE_VALUE; + + if (!strchr(newline, c)) { + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } + + value[n_value++] = c; + } + break; + + case DOUBLE_QUOTE_VALUE: + if (c == '\"') + state = PRE_VALUE; + else if (c == '\\') + state = DOUBLE_QUOTE_VALUE_ESCAPE; + else { + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } + + value[n_value++] = c; + } + + break; + + case DOUBLE_QUOTE_VALUE_ESCAPE: + state = DOUBLE_QUOTE_VALUE; + + if (!strchr(newline, c)) { + if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) { + r = -ENOMEM; + goto fail; + } + + value[n_value++] = c; + } + break; + + case COMMENT: + if (c == '\\') + state = COMMENT_ESCAPE; + else if (strchr(newline, c)) { + state = PRE_KEY; + line ++; + } + break; + + case COMMENT_ESCAPE: + state = COMMENT; + break; + } + } + + if (state == PRE_VALUE || + state == VALUE || + state == VALUE_ESCAPE || + state == SINGLE_QUOTE_VALUE || + state == SINGLE_QUOTE_VALUE_ESCAPE || + state == DOUBLE_QUOTE_VALUE || + state == DOUBLE_QUOTE_VALUE_ESCAPE) { + + key[n_key] = 0; + + if (value) + value[n_value] = 0; + + if (state == VALUE) + if (last_value_whitespace != (size_t) -1) + value[last_value_whitespace] = 0; + + /* strip trailing whitespace from key */ + if (last_key_whitespace != (size_t) -1) + key[last_key_whitespace] = 0; + + r = push(fname, line, key, value, userdata, n_pushed); + if (r < 0) + goto fail; + } + + return 0; + +fail: + free(value); + return r; +} + +static int parse_env_file_push( + const char *filename, unsigned line, + const char *key, char *value, + void *userdata, + int *n_pushed) { + + const char *k; + va_list aq, *ap = userdata; + + if (!utf8_is_valid(key)) { + _cleanup_free_ char *p = NULL; + + p = utf8_escape_invalid(key); + log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", strna(filename), line, p); + return -EINVAL; + } + + if (value && !utf8_is_valid(value)) { + _cleanup_free_ char *p = NULL; + + p = utf8_escape_invalid(value); + log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, p); + return -EINVAL; + } + + va_copy(aq, *ap); + + while ((k = va_arg(aq, const char *))) { + char **v; + + v = va_arg(aq, char **); + + if (streq(key, k)) { + va_end(aq); + free(*v); + *v = value; + + if (n_pushed) + (*n_pushed)++; + + return 1; + } + } + + va_end(aq); + free(value); + + return 0; +} + +int parse_env_file( + const char *fname, + const char *newline, ...) { + + va_list ap; + int r, n_pushed = 0; + + if (!newline) + newline = NEWLINE; + + va_start(ap, newline); + r = parse_env_file_internal(NULL, fname, newline, parse_env_file_push, &ap, &n_pushed); + va_end(ap); + + return r < 0 ? r : n_pushed; +} + +static int load_env_file_push( + const char *filename, unsigned line, + const char *key, char *value, + void *userdata, + int *n_pushed) { + char ***m = userdata; + char *p; + int r; + + if (!utf8_is_valid(key)) { + _cleanup_free_ char *t = utf8_escape_invalid(key); + + log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t); + return -EINVAL; + } + + if (value && !utf8_is_valid(value)) { + _cleanup_free_ char *t = utf8_escape_invalid(value); + + log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t); + return -EINVAL; + } + + p = strjoin(key, "=", strempty(value), NULL); + if (!p) + return -ENOMEM; + + r = strv_consume(m, p); + if (r < 0) + return r; + + if (n_pushed) + (*n_pushed)++; + + free(value); + return 0; +} + +int load_env_file(FILE *f, const char *fname, const char *newline, char ***rl) { + char **m = NULL; + int r; + + if (!newline) + newline = NEWLINE; + + r = parse_env_file_internal(f, fname, newline, load_env_file_push, &m, NULL); + if (r < 0) { + strv_free(m); + return r; + } + + *rl = m; + return 0; +} + +static int load_env_file_push_pairs( + const char *filename, unsigned line, + const char *key, char *value, + void *userdata, + int *n_pushed) { + char ***m = userdata; + int r; + + if (!utf8_is_valid(key)) { + _cleanup_free_ char *t = utf8_escape_invalid(key); + + log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", strna(filename), line, t); + return -EINVAL; + } + + if (value && !utf8_is_valid(value)) { + _cleanup_free_ char *t = utf8_escape_invalid(value); + + log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", strna(filename), line, key, t); + return -EINVAL; + } + + r = strv_extend(m, key); + if (r < 0) + return -ENOMEM; + + if (!value) { + r = strv_extend(m, ""); + if (r < 0) + return -ENOMEM; + } else { + r = strv_push(m, value); + if (r < 0) + return r; + } + + if (n_pushed) + (*n_pushed)++; + + return 0; +} + +int load_env_file_pairs(FILE *f, const char *fname, const char *newline, char ***rl) { + char **m = NULL; + int r; + + if (!newline) + newline = NEWLINE; + + r = parse_env_file_internal(f, fname, newline, load_env_file_push_pairs, &m, NULL); + if (r < 0) { + strv_free(m); + return r; + } + + *rl = m; + return 0; +} + +static void write_env_var(FILE *f, const char *v) { + const char *p; + + p = strchr(v, '='); + if (!p) { + /* Fallback */ + fputs(v, f); + fputc('\n', f); + return; + } + + p++; + fwrite(v, 1, p-v, f); + + if (string_has_cc(p, NULL) || chars_intersect(p, WHITESPACE SHELL_NEED_QUOTES)) { + fputc('\"', f); + + for (; *p; p++) { + if (strchr(SHELL_NEED_ESCAPE, *p)) + fputc('\\', f); + + fputc(*p, f); + } + + fputc('\"', f); + } else + fputs(p, f); + + fputc('\n', f); +} + +int write_env_file(const char *fname, char **l) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *p = NULL; + char **i; + int r; + + assert(fname); + + r = fopen_temporary(fname, &f, &p); + if (r < 0) + return r; + + fchmod_umask(fileno(f), 0644); + + STRV_FOREACH(i, l) + write_env_var(f, *i); + + r = fflush_and_check(f); + if (r >= 0) { + if (rename(p, fname) >= 0) + return 0; + + r = -errno; + } + + unlink(p); + return r; +} + +int executable_is_script(const char *path, char **interpreter) { + int r; + _cleanup_free_ char *line = NULL; + int len; + char *ans; + + assert(path); + + r = read_one_line_file(path, &line); + if (r < 0) + return r; + + if (!startswith(line, "#!")) + return 0; + + ans = strstrip(line + 2); + len = strcspn(ans, " \t"); + + if (len == 0) + return 0; + + ans = strndup(ans, len); + if (!ans) + return -ENOMEM; + + *interpreter = ans; + return 1; +} + +/** + * Retrieve one field from a file like /proc/self/status. pattern + * should not include whitespace or the delimiter (':'). pattern matches only + * the beginning of a line. Whitespace before ':' is skipped. Whitespace and + * zeros after the ':' will be skipped. field must be freed afterwards. + * terminator specifies the terminating characters of the field value (not + * included in the value). + */ +int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field) { + _cleanup_free_ char *status = NULL; + char *t, *f; + size_t len; + int r; + + assert(terminator); + assert(filename); + assert(pattern); + assert(field); + + r = read_full_file(filename, &status, NULL); + if (r < 0) + return r; + + t = status; + + do { + bool pattern_ok; + + do { + t = strstr(t, pattern); + if (!t) + return -ENOENT; + + /* Check that pattern occurs in beginning of line. */ + pattern_ok = (t == status || t[-1] == '\n'); + + t += strlen(pattern); + + } while (!pattern_ok); + + t += strspn(t, " \t"); + if (!*t) + return -ENOENT; + + } while (*t != ':'); + + t++; + + if (*t) { + t += strspn(t, " \t"); + + /* Also skip zeros, because when this is used for + * capabilities, we don't want the zeros. This way the + * same capability set always maps to the same string, + * irrespective of the total capability set size. For + * other numbers it shouldn't matter. */ + t += strspn(t, "0"); + /* Back off one char if there's nothing but whitespace + and zeros */ + if (!*t || isspace(*t)) + t --; + } + + len = strcspn(t, terminator); + + f = strndup(t, len); + if (!f) + return -ENOMEM; + + *field = f; + return 0; +} + +DIR *xopendirat(int fd, const char *name, int flags) { + int nfd; + DIR *d; + + assert(!(flags & O_CREAT)); + + nfd = openat(fd, name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|flags, 0); + if (nfd < 0) + return NULL; + + d = fdopendir(nfd); + if (!d) { + safe_close(nfd); + return NULL; + } + + return d; +} + +#if 0 /* NM_IGNORED */ +static int search_and_fopen_internal(const char *path, const char *mode, const char *root, char **search, FILE **_f) { + char **i; + + assert(path); + assert(mode); + assert(_f); + + if (!path_strv_resolve_uniq(search, root)) + return -ENOMEM; + + STRV_FOREACH(i, search) { + _cleanup_free_ char *p = NULL; + FILE *f; + + if (root) + p = strjoin(root, *i, "/", path, NULL); + else + p = strjoin(*i, "/", path, NULL); + if (!p) + return -ENOMEM; + + f = fopen(p, mode); + if (f) { + *_f = f; + return 0; + } + + if (errno != ENOENT) + return -errno; + } + + return -ENOENT; +} + +int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f) { + _cleanup_strv_free_ char **copy = NULL; + + assert(path); + assert(mode); + assert(_f); + + if (path_is_absolute(path)) { + FILE *f; + + f = fopen(path, mode); + if (f) { + *_f = f; + return 0; + } + + return -errno; + } + + copy = strv_copy((char**) search); + if (!copy) + return -ENOMEM; + + return search_and_fopen_internal(path, mode, root, copy, _f); +} + +int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f) { + _cleanup_strv_free_ char **s = NULL; + + if (path_is_absolute(path)) { + FILE *f; + + f = fopen(path, mode); + if (f) { + *_f = f; + return 0; + } + + return -errno; + } + + s = strv_split_nulstr(search); + if (!s) + return -ENOMEM; + + return search_and_fopen_internal(path, mode, root, s, _f); +} +#endif /* NM_IGNORED */ + +int fopen_temporary(const char *path, FILE **_f, char **_temp_path) { + FILE *f; + char *t; + int r, fd; + + assert(path); + assert(_f); + assert(_temp_path); + + r = tempfn_xxxxxx(path, NULL, &t); + if (r < 0) + return r; + + fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC); + if (fd < 0) { + free(t); + return -errno; + } + + f = fdopen(fd, "we"); + if (!f) { + unlink_noerrno(t); + free(t); + safe_close(fd); + return -errno; + } + + *_f = f; + *_temp_path = t; + + return 0; +} + +int fflush_and_check(FILE *f) { + assert(f); + + errno = 0; + fflush(f); + + if (ferror(f)) + return errno ? -errno : -EIO; + + return 0; +} + +/* This is much like like mkostemp() but is subject to umask(). */ +int mkostemp_safe(char *pattern, int flags) { + _cleanup_umask_ mode_t u = 0; + int fd; + + assert(pattern); + + u = umask(077); + + fd = mkostemp(pattern, flags); + if (fd < 0) + return -errno; + + return fd; +} + +int open_tmpfile(const char *path, int flags) { + char *p; + int fd; + + assert(path); + +#ifdef O_TMPFILE + /* Try O_TMPFILE first, if it is supported */ + fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR); + if (fd >= 0) + return fd; +#endif + + /* Fall back to unguessable name + unlinking */ + p = strjoina(path, "/systemd-tmp-XXXXXX"); + + fd = mkostemp_safe(p, flags); + if (fd < 0) + return fd; + + unlink(p); + return fd; +} + +int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { + const char *fn; + char *t; + + assert(p); + assert(ret); + + /* + * Turns this: + * /foo/bar/waldo + * + * Into this: + * /foo/bar/.#waldoXXXXXX + */ + + fn = basename(p); + if (!filename_is_valid(fn)) + return -EINVAL; + + if (extra == NULL) + extra = ""; + + t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1); + if (!t) + return -ENOMEM; + + strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX"); + + *ret = path_kill_slashes(t); + return 0; +} + +int tempfn_random(const char *p, const char *extra, char **ret) { + const char *fn; + char *t, *x; + uint64_t u; + unsigned i; + + assert(p); + assert(ret); + + /* + * Turns this: + * /foo/bar/waldo + * + * Into this: + * /foo/bar/.#waldobaa2a261115984a9 + */ + + fn = basename(p); + if (!filename_is_valid(fn)) + return -EINVAL; + + if (!extra) + extra = ""; + + t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1); + if (!t) + return -ENOMEM; + + x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn); + + u = random_u64(); + for (i = 0; i < 16; i++) { + *(x++) = hexchar(u & 0xF); + u >>= 4; + } + + *x = 0; + + *ret = path_kill_slashes(t); + return 0; +} + +int tempfn_random_child(const char *p, const char *extra, char **ret) { + char *t, *x; + uint64_t u; + unsigned i; + + assert(p); + assert(ret); + + /* Turns this: + * /foo/bar/waldo + * Into this: + * /foo/bar/waldo/.#3c2b6219aa75d7d0 + */ + + if (!extra) + extra = ""; + + t = new(char, strlen(p) + 3 + strlen(extra) + 16 + 1); + if (!t) + return -ENOMEM; + + x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra); + + u = random_u64(); + for (i = 0; i < 16; i++) { + *(x++) = hexchar(u & 0xF); + u >>= 4; + } + + *x = 0; + + *ret = path_kill_slashes(t); + return 0; +} + +#if 0 /* NM_IGNORED */ +int write_timestamp_file_atomic(const char *fn, usec_t n) { + char ln[DECIMAL_STR_MAX(n)+2]; + + /* Creates a "timestamp" file, that contains nothing but a + * usec_t timestamp, formatted in ASCII. */ + + if (n <= 0 || n >= USEC_INFINITY) + return -ERANGE; + + xsprintf(ln, USEC_FMT "\n", n); + + return write_string_file(fn, ln, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); +} +#endif /* NM_IGNORED */ + +int read_timestamp_file(const char *fn, usec_t *ret) { + _cleanup_free_ char *ln = NULL; + uint64_t t; + int r; + + r = read_one_line_file(fn, &ln); + if (r < 0) + return r; + + r = safe_atou64(ln, &t); + if (r < 0) + return r; + + if (t <= 0 || t >= (uint64_t) USEC_INFINITY) + return -ERANGE; + + *ret = (usec_t) t; + return 0; +} diff --git a/src/systemd/src/basic/fileio.h b/src/systemd/src/basic/fileio.h new file mode 100644 index 00000000..daaa7802 --- /dev/null +++ b/src/systemd/src/basic/fileio.h @@ -0,0 +1,86 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include + +#include "macro.h" +#include "time-util.h" + +typedef enum { + WRITE_STRING_FILE_CREATE = 1, + WRITE_STRING_FILE_ATOMIC = 2, + WRITE_STRING_FILE_AVOID_NEWLINE = 4, + WRITE_STRING_FILE_VERIFY_ON_FAILURE = 8, +} WriteStringFileFlags; + +int write_string_stream(FILE *f, const char *line, bool enforce_newline); +int write_string_file(const char *fn, const char *line, WriteStringFileFlags flags); + +int read_one_line_file(const char *fn, char **line); +int read_full_file(const char *fn, char **contents, size_t *size); +int read_full_stream(FILE *f, char **contents, size_t *size); + +int verify_file(const char *fn, const char *blob, bool accept_extra_nl); + +int parse_env_file(const char *fname, const char *separator, ...) _sentinel_; +int load_env_file(FILE *f, const char *fname, const char *separator, char ***l); +int load_env_file_pairs(FILE *f, const char *fname, const char *separator, char ***l); + +int write_env_file(const char *fname, char **l); + +int executable_is_script(const char *path, char **interpreter); + +int get_proc_field(const char *filename, const char *pattern, const char *terminator, char **field); + +DIR *xopendirat(int dirfd, const char *name, int flags); + +int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **_f); +int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **_f); + +#define FOREACH_LINE(line, f, on_error) \ + for (;;) \ + if (!fgets(line, sizeof(line), f)) { \ + if (ferror(f)) { \ + on_error; \ + } \ + break; \ + } else + +int fflush_and_check(FILE *f); + +int fopen_temporary(const char *path, FILE **_f, char **_temp_path); +int mkostemp_safe(char *pattern, int flags); +int open_tmpfile(const char *path, int flags); + +int tempfn_xxxxxx(const char *p, const char *extra, char **ret); +int tempfn_random(const char *p, const char *extra, char **ret); +int tempfn_random_child(const char *p, const char *extra, char **ret); + +int write_timestamp_file_atomic(const char *fn, usec_t n); +int read_timestamp_file(const char *fn, usec_t *ret); diff --git a/src/systemd/src/basic/fs-util.c b/src/systemd/src/basic/fs-util.c new file mode 100644 index 00000000..741bd31f --- /dev/null +++ b/src/systemd/src/basic/fs-util.c @@ -0,0 +1,526 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alloc-util.h" +#if 0 /* NM_IGNORED */ +#include "dirent-util.h" +#endif /* NM_IGNORED */ +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "log.h" +#include "macro.h" +#if 0 /* NM_IGNORED */ +#include "missing.h" +#include "mkdir.h" +#endif /* NM_IGNORED */ +#include "parse-util.h" +#include "path-util.h" +#include "string-util.h" +#include "strv.h" +#include "time-util.h" +#if 0 /* NM_IGNORED */ +#include "user-util.h" +#endif /* NM_IGNORED */ +#include "util.h" + +int unlink_noerrno(const char *path) { + PROTECT_ERRNO; + int r; + + r = unlink(path); + if (r < 0) + return -errno; + + return 0; +} + +#if 0 /* NM_IGNORED */ +int rmdir_parents(const char *path, const char *stop) { + size_t l; + int r = 0; + + assert(path); + assert(stop); + + l = strlen(path); + + /* Skip trailing slashes */ + while (l > 0 && path[l-1] == '/') + l--; + + while (l > 0) { + char *t; + + /* Skip last component */ + while (l > 0 && path[l-1] != '/') + l--; + + /* Skip trailing slashes */ + while (l > 0 && path[l-1] == '/') + l--; + + if (l <= 0) + break; + + t = strndup(path, l); + if (!t) + return -ENOMEM; + + if (path_startswith(stop, t)) { + free(t); + return 0; + } + + r = rmdir(t); + free(t); + + if (r < 0) + if (errno != ENOENT) + return -errno; + } + + return 0; +} + + +int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { + struct stat buf; + int ret; + + ret = renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_NOREPLACE); + if (ret >= 0) + return 0; + + /* renameat2() exists since Linux 3.15, btrfs added support for it later. + * If it is not implemented, fallback to another method. */ + if (!IN_SET(errno, EINVAL, ENOSYS)) + return -errno; + + /* The link()/unlink() fallback does not work on directories. But + * renameat() without RENAME_NOREPLACE gives the same semantics on + * directories, except when newpath is an *empty* directory. This is + * good enough. */ + ret = fstatat(olddirfd, oldpath, &buf, AT_SYMLINK_NOFOLLOW); + if (ret >= 0 && S_ISDIR(buf.st_mode)) { + ret = renameat(olddirfd, oldpath, newdirfd, newpath); + return ret >= 0 ? 0 : -errno; + } + + /* If it is not a directory, use the link()/unlink() fallback. */ + ret = linkat(olddirfd, oldpath, newdirfd, newpath, 0); + if (ret < 0) + return -errno; + + ret = unlinkat(olddirfd, oldpath, 0); + if (ret < 0) { + /* backup errno before the following unlinkat() alters it */ + ret = errno; + (void) unlinkat(newdirfd, newpath, 0); + errno = ret; + return -errno; + } + + return 0; +} + +int readlinkat_malloc(int fd, const char *p, char **ret) { + size_t l = 100; + int r; + + assert(p); + assert(ret); + + for (;;) { + char *c; + ssize_t n; + + c = new(char, l); + if (!c) + return -ENOMEM; + + n = readlinkat(fd, p, c, l-1); + if (n < 0) { + r = -errno; + free(c); + return r; + } + + if ((size_t) n < l-1) { + c[n] = 0; + *ret = c; + return 0; + } + + free(c); + l *= 2; + } +} + +int readlink_malloc(const char *p, char **ret) { + return readlinkat_malloc(AT_FDCWD, p, ret); +} + +int readlink_value(const char *p, char **ret) { + _cleanup_free_ char *link = NULL; + char *value; + int r; + + r = readlink_malloc(p, &link); + if (r < 0) + return r; + + value = basename(link); + if (!value) + return -ENOENT; + + value = strdup(value); + if (!value) + return -ENOMEM; + + *ret = value; + + return 0; +} + +int readlink_and_make_absolute(const char *p, char **r) { + _cleanup_free_ char *target = NULL; + char *k; + int j; + + assert(p); + assert(r); + + j = readlink_malloc(p, &target); + if (j < 0) + return j; + + k = file_in_same_dir(p, target); + if (!k) + return -ENOMEM; + + *r = k; + return 0; +} + +int readlink_and_canonicalize(const char *p, char **r) { + char *t, *s; + int j; + + assert(p); + assert(r); + + j = readlink_and_make_absolute(p, &t); + if (j < 0) + return j; + + s = canonicalize_file_name(t); + if (s) { + free(t); + *r = s; + } else + *r = t; + + path_kill_slashes(*r); + + return 0; +} + +int readlink_and_make_absolute_root(const char *root, const char *path, char **ret) { + _cleanup_free_ char *target = NULL, *t = NULL; + const char *full; + int r; + + full = prefix_roota(root, path); + r = readlink_malloc(full, &target); + if (r < 0) + return r; + + t = file_in_same_dir(path, target); + if (!t) + return -ENOMEM; + + *ret = t; + t = NULL; + + return 0; +} + +int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) { + assert(path); + + /* Under the assumption that we are running privileged we + * first change the access mode and only then hand out + * ownership to avoid a window where access is too open. */ + + if (mode != MODE_INVALID) + if (chmod(path, mode) < 0) + return -errno; + + if (uid != UID_INVALID || gid != GID_INVALID) + if (chown(path, uid, gid) < 0) + return -errno; + + return 0; +} + +int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) { + assert(fd >= 0); + + /* Under the assumption that we are running privileged we + * first change the access mode and only then hand out + * ownership to avoid a window where access is too open. */ + + if (mode != MODE_INVALID) + if (fchmod(fd, mode) < 0) + return -errno; + + if (uid != UID_INVALID || gid != GID_INVALID) + if (fchown(fd, uid, gid) < 0) + return -errno; + + return 0; +} +#endif /* NM_IGNORED */ + +int fchmod_umask(int fd, mode_t m) { + mode_t u; + int r; + + u = umask(0777); + r = fchmod(fd, m & (~u)) < 0 ? -errno : 0; + umask(u); + + return r; +} + +#if 0 /* NM_IGNORED */ +int fd_warn_permissions(const char *path, int fd) { + struct stat st; + + if (fstat(fd, &st) < 0) + return -errno; + + if (st.st_mode & 0111) + log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path); + + if (st.st_mode & 0002) + log_warning("Configuration file %s is marked world-writable. Please remove world writability permission bits. Proceeding anyway.", path); + + if (getpid() == 1 && (st.st_mode & 0044) != 0044) + log_warning("Configuration file %s is marked world-inaccessible. This has no effect as configuration data is accessible via APIs without restrictions. Proceeding anyway.", path); + + return 0; +} + +int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) { + _cleanup_close_ int fd; + int r; + + assert(path); + + if (parents) + mkdir_parents(path, 0755); + + fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644); + if (fd < 0) + return -errno; + + if (mode != MODE_INVALID) { + r = fchmod(fd, mode); + if (r < 0) + return -errno; + } + + if (uid != UID_INVALID || gid != GID_INVALID) { + r = fchown(fd, uid, gid); + if (r < 0) + return -errno; + } + + if (stamp != USEC_INFINITY) { + struct timespec ts[2]; + + timespec_store(&ts[0], stamp); + ts[1] = ts[0]; + r = futimens(fd, ts); + } else + r = futimens(fd, NULL); + if (r < 0) + return -errno; + + return 0; +} + +int touch(const char *path) { + return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID); +} + +int symlink_idempotent(const char *from, const char *to) { + _cleanup_free_ char *p = NULL; + int r; + + assert(from); + assert(to); + + if (symlink(from, to) < 0) { + if (errno != EEXIST) + return -errno; + + r = readlink_malloc(to, &p); + if (r < 0) + return r; + + if (!streq(p, from)) + return -EINVAL; + } + + return 0; +} + +int symlink_atomic(const char *from, const char *to) { + _cleanup_free_ char *t = NULL; + int r; + + assert(from); + assert(to); + + r = tempfn_random(to, NULL, &t); + if (r < 0) + return r; + + if (symlink(from, t) < 0) + return -errno; + + if (rename(t, to) < 0) { + unlink_noerrno(t); + return -errno; + } + + return 0; +} + +int mknod_atomic(const char *path, mode_t mode, dev_t dev) { + _cleanup_free_ char *t = NULL; + int r; + + assert(path); + + r = tempfn_random(path, NULL, &t); + if (r < 0) + return r; + + if (mknod(t, mode, dev) < 0) + return -errno; + + if (rename(t, path) < 0) { + unlink_noerrno(t); + return -errno; + } + + return 0; +} + +int mkfifo_atomic(const char *path, mode_t mode) { + _cleanup_free_ char *t = NULL; + int r; + + assert(path); + + r = tempfn_random(path, NULL, &t); + if (r < 0) + return r; + + if (mkfifo(t, mode) < 0) + return -errno; + + if (rename(t, path) < 0) { + unlink_noerrno(t); + return -errno; + } + + return 0; +} + +int get_files_in_directory(const char *path, char ***list) { + _cleanup_closedir_ DIR *d = NULL; + size_t bufsize = 0, n = 0; + _cleanup_strv_free_ char **l = NULL; + + assert(path); + + /* Returns all files in a directory in *list, and the number + * of files as return value. If list is NULL returns only the + * number. */ + + d = opendir(path); + if (!d) + return -errno; + + for (;;) { + struct dirent *de; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return -errno; + if (!de) + break; + + dirent_ensure_type(d, de); + + if (!dirent_is_file(de)) + continue; + + if (list) { + /* one extra slot is needed for the terminating NULL */ + if (!GREEDY_REALLOC(l, bufsize, n + 2)) + return -ENOMEM; + + l[n] = strdup(de->d_name); + if (!l[n]) + return -ENOMEM; + + l[++n] = NULL; + } else + n++; + } + + if (list) { + *list = l; + l = NULL; /* avoid freeing */ + } + + return n; +} +#endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/fs-util.h b/src/systemd/src/basic/fs-util.h new file mode 100644 index 00000000..d13c0194 --- /dev/null +++ b/src/systemd/src/basic/fs-util.h @@ -0,0 +1,79 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "time-util.h" + +int unlink_noerrno(const char *path); + +int rmdir_parents(const char *path, const char *stop); + +int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); + +int readlinkat_malloc(int fd, const char *p, char **ret); +int readlink_malloc(const char *p, char **r); +int readlink_value(const char *p, char **ret); +int readlink_and_make_absolute(const char *p, char **r); +int readlink_and_canonicalize(const char *p, char **r); +int readlink_and_make_absolute_root(const char *root, const char *path, char **ret); + +int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid); +int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid); + +int fchmod_umask(int fd, mode_t mode); + +int fd_warn_permissions(const char *path, int fd); + +#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW) + +int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode); +int touch(const char *path); + +int symlink_idempotent(const char *from, const char *to); + +int symlink_atomic(const char *from, const char *to); +int mknod_atomic(const char *path, mode_t mode, dev_t dev); +int mkfifo_atomic(const char *path, mode_t mode); + +int get_files_in_directory(const char *path, char ***list); + +#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1) + +#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \ + for ((e) = &buffer.ev; \ + (uint8_t*) (e) < (uint8_t*) (buffer.raw) + (sz); \ + (e) = (struct inotify_event*) ((uint8_t*) (e) + sizeof(struct inotify_event) + (e)->len)) + +union inotify_event_buffer { + struct inotify_event ev; + uint8_t raw[INOTIFY_EVENT_MAX]; +}; diff --git a/src/systemd/src/basic/hashmap.c b/src/systemd/src/basic/hashmap.c new file mode 100644 index 00000000..4ebb73b5 --- /dev/null +++ b/src/systemd/src/basic/hashmap.c @@ -0,0 +1,1871 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2014 Michal Schmidt + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "alloc-util.h" +#include "hashmap.h" +#include "macro.h" +#include "mempool.h" +#if 0 /* NM_IGNORED */ +#include "process-util.h" +#endif /* NM_IGNORED */ +#include "random-util.h" +#include "set.h" +#include "siphash24.h" +#include "strv.h" +#include "util.h" + +#ifdef ENABLE_DEBUG_HASHMAP +#include +#include "list.h" +#endif + +/* + * Implementation of hashmaps. + * Addressing: open + * - uses less RAM compared to closed addressing (chaining), because + * our entries are small (especially in Sets, which tend to contain + * the majority of entries in systemd). + * Collision resolution: Robin Hood + * - tends to equalize displacement of entries from their optimal buckets. + * Probe sequence: linear + * - though theoretically worse than random probing/uniform hashing/double + * hashing, it is good for cache locality. + * + * References: + * Celis, P. 1986. Robin Hood Hashing. + * Ph.D. Dissertation. University of Waterloo, Waterloo, Ont., Canada, Canada. + * https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf + * - The results are derived for random probing. Suggests deletion with + * tombstones and two mean-centered search methods. None of that works + * well for linear probing. + * + * Janson, S. 2005. Individual displacements for linear probing hashing with different insertion policies. + * ACM Trans. Algorithms 1, 2 (October 2005), 177-213. + * DOI=10.1145/1103963.1103964 http://doi.acm.org/10.1145/1103963.1103964 + * http://www.math.uu.se/~svante/papers/sj157.pdf + * - Applies to Robin Hood with linear probing. Contains remarks on + * the unsuitability of mean-centered search with linear probing. + * + * Viola, A. 2005. Exact distribution of individual displacements in linear probing hashing. + * ACM Trans. Algorithms 1, 2 (October 2005), 214-242. + * DOI=10.1145/1103963.1103965 http://doi.acm.org/10.1145/1103963.1103965 + * - Similar to Janson. Note that Viola writes about C_{m,n} (number of probes + * in a successful search), and Janson writes about displacement. C = d + 1. + * + * Goossaert, E. 2013. Robin Hood hashing: backward shift deletion. + * http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/ + * - Explanation of backward shift deletion with pictures. + * + * Khuong, P. 2013. The Other Robin Hood Hashing. + * http://www.pvk.ca/Blog/2013/11/26/the-other-robin-hood-hashing/ + * - Short summary of random vs. linear probing, and tombstones vs. backward shift. + */ + +/* + * XXX Ideas for improvement: + * For unordered hashmaps, randomize iteration order, similarly to Perl: + * http://blog.booking.com/hardening-perls-hash-function.html + */ + +/* INV_KEEP_FREE = 1 / (1 - max_load_factor) + * e.g. 1 / (1 - 0.8) = 5 ... keep one fifth of the buckets free. */ +#define INV_KEEP_FREE 5U + +/* Fields common to entries of all hashmap/set types */ +struct hashmap_base_entry { + const void *key; +}; + +/* Entry types for specific hashmap/set types + * hashmap_base_entry must be at the beginning of each entry struct. */ + +struct plain_hashmap_entry { + struct hashmap_base_entry b; + void *value; +}; + +struct ordered_hashmap_entry { + struct plain_hashmap_entry p; + unsigned iterate_next, iterate_previous; +}; + +struct set_entry { + struct hashmap_base_entry b; +}; + +/* In several functions it is advantageous to have the hash table extended + * virtually by a couple of additional buckets. We reserve special index values + * for these "swap" buckets. */ +#define _IDX_SWAP_BEGIN (UINT_MAX - 3) +#define IDX_PUT (_IDX_SWAP_BEGIN + 0) +#define IDX_TMP (_IDX_SWAP_BEGIN + 1) +#define _IDX_SWAP_END (_IDX_SWAP_BEGIN + 2) + +#define IDX_FIRST (UINT_MAX - 1) /* special index for freshly initialized iterators */ +#define IDX_NIL UINT_MAX /* special index value meaning "none" or "end" */ + +assert_cc(IDX_FIRST == _IDX_SWAP_END); +assert_cc(IDX_FIRST == _IDX_ITERATOR_FIRST); + +/* Storage space for the "swap" buckets. + * All entry types can fit into a ordered_hashmap_entry. */ +struct swap_entries { + struct ordered_hashmap_entry e[_IDX_SWAP_END - _IDX_SWAP_BEGIN]; +}; + +/* Distance from Initial Bucket */ +typedef uint8_t dib_raw_t; +#define DIB_RAW_OVERFLOW ((dib_raw_t)0xfdU) /* indicates DIB value is greater than representable */ +#define DIB_RAW_REHASH ((dib_raw_t)0xfeU) /* entry yet to be rehashed during in-place resize */ +#define DIB_RAW_FREE ((dib_raw_t)0xffU) /* a free bucket */ +#define DIB_RAW_INIT ((char)DIB_RAW_FREE) /* a byte to memset a DIB store with when initializing */ + +#define DIB_FREE UINT_MAX + +#ifdef ENABLE_DEBUG_HASHMAP +struct hashmap_debug_info { + LIST_FIELDS(struct hashmap_debug_info, debug_list); + unsigned max_entries; /* high watermark of n_entries */ + + /* who allocated this hashmap */ + int line; + const char *file; + const char *func; + + /* fields to detect modification while iterating */ + unsigned put_count; /* counts puts into the hashmap */ + unsigned rem_count; /* counts removals from hashmap */ + unsigned last_rem_idx; /* remembers last removal index */ +}; + +/* Tracks all existing hashmaps. Get at it from gdb. See sd_dump_hashmaps.py */ +static LIST_HEAD(struct hashmap_debug_info, hashmap_debug_list); +static pthread_mutex_t hashmap_debug_list_mutex = PTHREAD_MUTEX_INITIALIZER; + +#define HASHMAP_DEBUG_FIELDS struct hashmap_debug_info debug; + +#else /* !ENABLE_DEBUG_HASHMAP */ +#define HASHMAP_DEBUG_FIELDS +#endif /* ENABLE_DEBUG_HASHMAP */ + +enum HashmapType { + HASHMAP_TYPE_PLAIN, + HASHMAP_TYPE_ORDERED, + HASHMAP_TYPE_SET, + _HASHMAP_TYPE_MAX +}; + +struct _packed_ indirect_storage { + char *storage; /* where buckets and DIBs are stored */ + uint8_t hash_key[HASH_KEY_SIZE]; /* hash key; changes during resize */ + + unsigned n_entries; /* number of stored entries */ + unsigned n_buckets; /* number of buckets */ + + unsigned idx_lowest_entry; /* Index below which all buckets are free. + Makes "while(hashmap_steal_first())" loops + O(n) instead of O(n^2) for unordered hashmaps. */ + uint8_t _pad[3]; /* padding for the whole HashmapBase */ + /* The bitfields in HashmapBase complete the alignment of the whole thing. */ +}; + +struct direct_storage { + /* This gives us 39 bytes on 64bit, or 35 bytes on 32bit. + * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit, + * or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */ + char storage[sizeof(struct indirect_storage)]; +}; + +#define DIRECT_BUCKETS(entry_t) \ + (sizeof(struct direct_storage) / (sizeof(entry_t) + sizeof(dib_raw_t))) + +/* We should be able to store at least one entry directly. */ +assert_cc(DIRECT_BUCKETS(struct ordered_hashmap_entry) >= 1); + +/* We have 3 bits for n_direct_entries. */ +assert_cc(DIRECT_BUCKETS(struct set_entry) < (1 << 3)); + +/* Hashmaps with directly stored entries all use this shared hash key. + * It's no big deal if the key is guessed, because there can be only + * a handful of directly stored entries in a hashmap. When a hashmap + * outgrows direct storage, it gets its own key for indirect storage. */ +static uint8_t shared_hash_key[HASH_KEY_SIZE]; +static bool shared_hash_key_initialized; + +/* Fields that all hashmap/set types must have */ +struct HashmapBase { + const struct hash_ops *hash_ops; /* hash and compare ops to use */ + + union _packed_ { + struct indirect_storage indirect; /* if has_indirect */ + struct direct_storage direct; /* if !has_indirect */ + }; + + enum HashmapType type:2; /* HASHMAP_TYPE_* */ + bool has_indirect:1; /* whether indirect storage is used */ + unsigned n_direct_entries:3; /* Number of entries in direct storage. + * Only valid if !has_indirect. */ + bool from_pool:1; /* whether was allocated from mempool */ + HASHMAP_DEBUG_FIELDS /* optional hashmap_debug_info */ +}; + +/* Specific hash types + * HashmapBase must be at the beginning of each hashmap struct. */ + +struct Hashmap { + struct HashmapBase b; +}; + +struct OrderedHashmap { + struct HashmapBase b; + unsigned iterate_list_head, iterate_list_tail; +}; + +struct Set { + struct HashmapBase b; +}; + +DEFINE_MEMPOOL(hashmap_pool, Hashmap, 8); +DEFINE_MEMPOOL(ordered_hashmap_pool, OrderedHashmap, 8); +/* No need for a separate Set pool */ +assert_cc(sizeof(Hashmap) == sizeof(Set)); + +struct hashmap_type_info { + size_t head_size; + size_t entry_size; + struct mempool *mempool; + unsigned n_direct_buckets; +}; + +static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = { + [HASHMAP_TYPE_PLAIN] = { + .head_size = sizeof(Hashmap), + .entry_size = sizeof(struct plain_hashmap_entry), + .mempool = &hashmap_pool, + .n_direct_buckets = DIRECT_BUCKETS(struct plain_hashmap_entry), + }, + [HASHMAP_TYPE_ORDERED] = { + .head_size = sizeof(OrderedHashmap), + .entry_size = sizeof(struct ordered_hashmap_entry), + .mempool = &ordered_hashmap_pool, + .n_direct_buckets = DIRECT_BUCKETS(struct ordered_hashmap_entry), + }, + [HASHMAP_TYPE_SET] = { + .head_size = sizeof(Set), + .entry_size = sizeof(struct set_entry), + .mempool = &hashmap_pool, + .n_direct_buckets = DIRECT_BUCKETS(struct set_entry), + }, +}; + +void string_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, strlen(p) + 1, state); +} + +int string_compare_func(const void *a, const void *b) { + return strcmp(a, b); +} + +const struct hash_ops string_hash_ops = { + .hash = string_hash_func, + .compare = string_compare_func +}; + +void trivial_hash_func(const void *p, struct siphash *state) { + siphash24_compress(&p, sizeof(p), state); +} + +int trivial_compare_func(const void *a, const void *b) { + return a < b ? -1 : (a > b ? 1 : 0); +} + +const struct hash_ops trivial_hash_ops = { + .hash = trivial_hash_func, + .compare = trivial_compare_func +}; + +void uint64_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, sizeof(uint64_t), state); +} + +int uint64_compare_func(const void *_a, const void *_b) { + uint64_t a, b; + a = *(const uint64_t*) _a; + b = *(const uint64_t*) _b; + return a < b ? -1 : (a > b ? 1 : 0); +} + +const struct hash_ops uint64_hash_ops = { + .hash = uint64_hash_func, + .compare = uint64_compare_func +}; + +#if SIZEOF_DEV_T != 8 +void devt_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, sizeof(dev_t), state); +} + +int devt_compare_func(const void *_a, const void *_b) { + dev_t a, b; + a = *(const dev_t*) _a; + b = *(const dev_t*) _b; + return a < b ? -1 : (a > b ? 1 : 0); +} + +const struct hash_ops devt_hash_ops = { + .hash = devt_hash_func, + .compare = devt_compare_func +}; +#endif + +static unsigned n_buckets(HashmapBase *h) { + return h->has_indirect ? h->indirect.n_buckets + : hashmap_type_info[h->type].n_direct_buckets; +} + +static unsigned n_entries(HashmapBase *h) { + return h->has_indirect ? h->indirect.n_entries + : h->n_direct_entries; +} + +static void n_entries_inc(HashmapBase *h) { + if (h->has_indirect) + h->indirect.n_entries++; + else + h->n_direct_entries++; +} + +static void n_entries_dec(HashmapBase *h) { + if (h->has_indirect) + h->indirect.n_entries--; + else + h->n_direct_entries--; +} + +static char *storage_ptr(HashmapBase *h) { + return h->has_indirect ? h->indirect.storage + : h->direct.storage; +} + +static uint8_t *hash_key(HashmapBase *h) { + return h->has_indirect ? h->indirect.hash_key + : shared_hash_key; +} + +static unsigned base_bucket_hash(HashmapBase *h, const void *p) { + struct siphash state; + uint64_t hash; + + siphash24_init(&state, hash_key(h)); + + h->hash_ops->hash(p, &state); + + hash = siphash24_finalize(&state); + + return (unsigned) (hash % n_buckets(h)); +} +#define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p) + +static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) { + static uint8_t current[HASH_KEY_SIZE]; + static bool current_initialized = false; + + /* Returns a hash function key to use. In order to keep things + * fast we will not generate a new key each time we allocate a + * new hash table. Instead, we'll just reuse the most recently + * generated one, except if we never generated one or when we + * are rehashing an entire hash table because we reached a + * fill level */ + + if (!current_initialized || !reuse_is_ok) { + random_bytes(current, sizeof(current)); + current_initialized = true; + } + + memcpy(hash_key, current, sizeof(current)); +} + +static struct hashmap_base_entry *bucket_at(HashmapBase *h, unsigned idx) { + return (struct hashmap_base_entry*) + (storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size); +} + +static struct plain_hashmap_entry *plain_bucket_at(Hashmap *h, unsigned idx) { + return (struct plain_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx); +} + +static struct ordered_hashmap_entry *ordered_bucket_at(OrderedHashmap *h, unsigned idx) { + return (struct ordered_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx); +} + +static struct set_entry *set_bucket_at(Set *h, unsigned idx) { + return (struct set_entry*) bucket_at(HASHMAP_BASE(h), idx); +} + +static struct ordered_hashmap_entry *bucket_at_swap(struct swap_entries *swap, unsigned idx) { + return &swap->e[idx - _IDX_SWAP_BEGIN]; +} + +/* Returns a pointer to the bucket at index idx. + * Understands real indexes and swap indexes, hence "_virtual". */ +static struct hashmap_base_entry *bucket_at_virtual(HashmapBase *h, struct swap_entries *swap, + unsigned idx) { + if (idx < _IDX_SWAP_BEGIN) + return bucket_at(h, idx); + + if (idx < _IDX_SWAP_END) + return &bucket_at_swap(swap, idx)->p.b; + + assert_not_reached("Invalid index"); +} + +static dib_raw_t *dib_raw_ptr(HashmapBase *h) { + return (dib_raw_t*) + (storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h)); +} + +static unsigned bucket_distance(HashmapBase *h, unsigned idx, unsigned from) { + return idx >= from ? idx - from + : n_buckets(h) + idx - from; +} + +static unsigned bucket_calculate_dib(HashmapBase *h, unsigned idx, dib_raw_t raw_dib) { + unsigned initial_bucket; + + if (raw_dib == DIB_RAW_FREE) + return DIB_FREE; + + if (_likely_(raw_dib < DIB_RAW_OVERFLOW)) + return raw_dib; + + /* + * Having an overflow DIB value is very unlikely. The hash function + * would have to be bad. For example, in a table of size 2^24 filled + * to load factor 0.9 the maximum observed DIB is only about 60. + * In theory (assuming I used Maxima correctly), for an infinite size + * hash table with load factor 0.8 the probability of a given entry + * having DIB > 40 is 1.9e-8. + * This returns the correct DIB value by recomputing the hash value in + * the unlikely case. XXX Hitting this case could be a hint to rehash. + */ + initial_bucket = bucket_hash(h, bucket_at(h, idx)->key); + return bucket_distance(h, idx, initial_bucket); +} + +static void bucket_set_dib(HashmapBase *h, unsigned idx, unsigned dib) { + dib_raw_ptr(h)[idx] = dib != DIB_FREE ? MIN(dib, DIB_RAW_OVERFLOW) : DIB_RAW_FREE; +} + +static unsigned skip_free_buckets(HashmapBase *h, unsigned idx) { + dib_raw_t *dibs; + + dibs = dib_raw_ptr(h); + + for ( ; idx < n_buckets(h); idx++) + if (dibs[idx] != DIB_RAW_FREE) + return idx; + + return IDX_NIL; +} + +static void bucket_mark_free(HashmapBase *h, unsigned idx) { + memzero(bucket_at(h, idx), hashmap_type_info[h->type].entry_size); + bucket_set_dib(h, idx, DIB_FREE); +} + +static void bucket_move_entry(HashmapBase *h, struct swap_entries *swap, + unsigned from, unsigned to) { + struct hashmap_base_entry *e_from, *e_to; + + assert(from != to); + + e_from = bucket_at_virtual(h, swap, from); + e_to = bucket_at_virtual(h, swap, to); + + memcpy(e_to, e_from, hashmap_type_info[h->type].entry_size); + + if (h->type == HASHMAP_TYPE_ORDERED) { + OrderedHashmap *lh = (OrderedHashmap*) h; + struct ordered_hashmap_entry *le, *le_to; + + le_to = (struct ordered_hashmap_entry*) e_to; + + if (le_to->iterate_next != IDX_NIL) { + le = (struct ordered_hashmap_entry*) + bucket_at_virtual(h, swap, le_to->iterate_next); + le->iterate_previous = to; + } + + if (le_to->iterate_previous != IDX_NIL) { + le = (struct ordered_hashmap_entry*) + bucket_at_virtual(h, swap, le_to->iterate_previous); + le->iterate_next = to; + } + + if (lh->iterate_list_head == from) + lh->iterate_list_head = to; + if (lh->iterate_list_tail == from) + lh->iterate_list_tail = to; + } +} + +static unsigned next_idx(HashmapBase *h, unsigned idx) { + return (idx + 1U) % n_buckets(h); +} + +static unsigned prev_idx(HashmapBase *h, unsigned idx) { + return (n_buckets(h) + idx - 1U) % n_buckets(h); +} + +static void *entry_value(HashmapBase *h, struct hashmap_base_entry *e) { + switch (h->type) { + + case HASHMAP_TYPE_PLAIN: + case HASHMAP_TYPE_ORDERED: + return ((struct plain_hashmap_entry*)e)->value; + + case HASHMAP_TYPE_SET: + return (void*) e->key; + + default: + assert_not_reached("Unknown hashmap type"); + } +} + +static void base_remove_entry(HashmapBase *h, unsigned idx) { + unsigned left, right, prev, dib; + dib_raw_t raw_dib, *dibs; + + dibs = dib_raw_ptr(h); + assert(dibs[idx] != DIB_RAW_FREE); + +#ifdef ENABLE_DEBUG_HASHMAP + h->debug.rem_count++; + h->debug.last_rem_idx = idx; +#endif + + left = idx; + /* Find the stop bucket ("right"). It is either free or has DIB == 0. */ + for (right = next_idx(h, left); ; right = next_idx(h, right)) { + raw_dib = dibs[right]; + if (raw_dib == 0 || raw_dib == DIB_RAW_FREE) + break; + + /* The buckets are not supposed to be all occupied and with DIB > 0. + * That would mean we could make everyone better off by shifting them + * backward. This scenario is impossible. */ + assert(left != right); + } + + if (h->type == HASHMAP_TYPE_ORDERED) { + OrderedHashmap *lh = (OrderedHashmap*) h; + struct ordered_hashmap_entry *le = ordered_bucket_at(lh, idx); + + if (le->iterate_next != IDX_NIL) + ordered_bucket_at(lh, le->iterate_next)->iterate_previous = le->iterate_previous; + else + lh->iterate_list_tail = le->iterate_previous; + + if (le->iterate_previous != IDX_NIL) + ordered_bucket_at(lh, le->iterate_previous)->iterate_next = le->iterate_next; + else + lh->iterate_list_head = le->iterate_next; + } + + /* Now shift all buckets in the interval (left, right) one step backwards */ + for (prev = left, left = next_idx(h, left); left != right; + prev = left, left = next_idx(h, left)) { + dib = bucket_calculate_dib(h, left, dibs[left]); + assert(dib != 0); + bucket_move_entry(h, NULL, left, prev); + bucket_set_dib(h, prev, dib - 1); + } + + bucket_mark_free(h, prev); + n_entries_dec(h); +} +#define remove_entry(h, idx) base_remove_entry(HASHMAP_BASE(h), idx) + +static unsigned hashmap_iterate_in_insertion_order(OrderedHashmap *h, Iterator *i) { + struct ordered_hashmap_entry *e; + unsigned idx; + + assert(h); + assert(i); + + if (i->idx == IDX_NIL) + goto at_end; + + if (i->idx == IDX_FIRST && h->iterate_list_head == IDX_NIL) + goto at_end; + + if (i->idx == IDX_FIRST) { + idx = h->iterate_list_head; + e = ordered_bucket_at(h, idx); + } else { + idx = i->idx; + e = ordered_bucket_at(h, idx); + /* + * We allow removing the current entry while iterating, but removal may cause + * a backward shift. The next entry may thus move one bucket to the left. + * To detect when it happens, we remember the key pointer of the entry we were + * going to iterate next. If it does not match, there was a backward shift. + */ + if (e->p.b.key != i->next_key) { + idx = prev_idx(HASHMAP_BASE(h), idx); + e = ordered_bucket_at(h, idx); + } + assert(e->p.b.key == i->next_key); + } + +#ifdef ENABLE_DEBUG_HASHMAP + i->prev_idx = idx; +#endif + + if (e->iterate_next != IDX_NIL) { + struct ordered_hashmap_entry *n; + i->idx = e->iterate_next; + n = ordered_bucket_at(h, i->idx); + i->next_key = n->p.b.key; + } else + i->idx = IDX_NIL; + + return idx; + +at_end: + i->idx = IDX_NIL; + return IDX_NIL; +} + +static unsigned hashmap_iterate_in_internal_order(HashmapBase *h, Iterator *i) { + unsigned idx; + + assert(h); + assert(i); + + if (i->idx == IDX_NIL) + goto at_end; + + if (i->idx == IDX_FIRST) { + /* fast forward to the first occupied bucket */ + if (h->has_indirect) { + i->idx = skip_free_buckets(h, h->indirect.idx_lowest_entry); + h->indirect.idx_lowest_entry = i->idx; + } else + i->idx = skip_free_buckets(h, 0); + + if (i->idx == IDX_NIL) + goto at_end; + } else { + struct hashmap_base_entry *e; + + assert(i->idx > 0); + + e = bucket_at(h, i->idx); + /* + * We allow removing the current entry while iterating, but removal may cause + * a backward shift. The next entry may thus move one bucket to the left. + * To detect when it happens, we remember the key pointer of the entry we were + * going to iterate next. If it does not match, there was a backward shift. + */ + if (e->key != i->next_key) + e = bucket_at(h, --i->idx); + + assert(e->key == i->next_key); + } + + idx = i->idx; +#ifdef ENABLE_DEBUG_HASHMAP + i->prev_idx = idx; +#endif + + i->idx = skip_free_buckets(h, i->idx + 1); + if (i->idx != IDX_NIL) + i->next_key = bucket_at(h, i->idx)->key; + else + i->idx = IDX_NIL; + + return idx; + +at_end: + i->idx = IDX_NIL; + return IDX_NIL; +} + +static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) { + if (!h) { + i->idx = IDX_NIL; + return IDX_NIL; + } + +#ifdef ENABLE_DEBUG_HASHMAP + if (i->idx == IDX_FIRST) { + i->put_count = h->debug.put_count; + i->rem_count = h->debug.rem_count; + } else { + /* While iterating, must not add any new entries */ + assert(i->put_count == h->debug.put_count); + /* ... or remove entries other than the current one */ + assert(i->rem_count == h->debug.rem_count || + (i->rem_count == h->debug.rem_count - 1 && + i->prev_idx == h->debug.last_rem_idx)); + /* Reset our removals counter */ + i->rem_count = h->debug.rem_count; + } +#endif + + return h->type == HASHMAP_TYPE_ORDERED ? hashmap_iterate_in_insertion_order((OrderedHashmap*) h, i) + : hashmap_iterate_in_internal_order(h, i); +} + +bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key) { + struct hashmap_base_entry *e; + void *data; + unsigned idx; + + idx = hashmap_iterate_entry(h, i); + if (idx == IDX_NIL) { + if (value) + *value = NULL; + if (key) + *key = NULL; + + return false; + } + + e = bucket_at(h, idx); + data = entry_value(h, e); + if (value) + *value = data; + if (key) + *key = e->key; + + return true; +} + +bool set_iterate(Set *s, Iterator *i, void **value) { + return internal_hashmap_iterate(HASHMAP_BASE(s), i, value, NULL); +} + +#define HASHMAP_FOREACH_IDX(idx, h, i) \ + for ((i) = ITERATOR_FIRST, (idx) = hashmap_iterate_entry((h), &(i)); \ + (idx != IDX_NIL); \ + (idx) = hashmap_iterate_entry((h), &(i))) + +static void reset_direct_storage(HashmapBase *h) { + const struct hashmap_type_info *hi = &hashmap_type_info[h->type]; + void *p; + + assert(!h->has_indirect); + + p = mempset(h->direct.storage, 0, hi->entry_size * hi->n_direct_buckets); + memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets); +} + +static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) { + HashmapBase *h; + const struct hashmap_type_info *hi = &hashmap_type_info[type]; + bool use_pool; + + use_pool = is_main_thread(); + + h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size); + + if (!h) + return NULL; + + h->type = type; + h->from_pool = use_pool; + h->hash_ops = hash_ops ? hash_ops : &trivial_hash_ops; + + if (type == HASHMAP_TYPE_ORDERED) { + OrderedHashmap *lh = (OrderedHashmap*)h; + lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL; + } + + reset_direct_storage(h); + + if (!shared_hash_key_initialized) { + random_bytes(shared_hash_key, sizeof(shared_hash_key)); + shared_hash_key_initialized= true; + } + +#ifdef ENABLE_DEBUG_HASHMAP + h->debug.func = func; + h->debug.file = file; + h->debug.line = line; + assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0); + LIST_PREPEND(debug_list, hashmap_debug_list, &h->debug); + assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0); +#endif + + return h; +} + +Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { + return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS); +} + +OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { + return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS); +} + +Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { + return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS); +} + +static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops *hash_ops, + enum HashmapType type HASHMAP_DEBUG_PARAMS) { + HashmapBase *q; + + assert(h); + + if (*h) + return 0; + + q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS); + if (!q) + return -ENOMEM; + + *h = q; + return 0; +} + +int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { + return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS); +} + +int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { + return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS); +} + +int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) { + return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS); +} + +static void hashmap_free_no_clear(HashmapBase *h) { + assert(!h->has_indirect); + assert(!h->n_direct_entries); + +#ifdef ENABLE_DEBUG_HASHMAP + assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0); + LIST_REMOVE(debug_list, hashmap_debug_list, &h->debug); + assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0); +#endif + + if (h->from_pool) + mempool_free_tile(hashmap_type_info[h->type].mempool, h); + else + free(h); +} + +HashmapBase *internal_hashmap_free(HashmapBase *h) { + + /* Free the hashmap, but nothing in it */ + + if (h) { + internal_hashmap_clear(h); + hashmap_free_no_clear(h); + } + + return NULL; +} + +HashmapBase *internal_hashmap_free_free(HashmapBase *h) { + + /* Free the hashmap and all data objects in it, but not the + * keys */ + + if (h) { + internal_hashmap_clear_free(h); + hashmap_free_no_clear(h); + } + + return NULL; +} + +Hashmap *hashmap_free_free_free(Hashmap *h) { + + /* Free the hashmap and all data and key objects in it */ + + if (h) { + hashmap_clear_free_free(h); + hashmap_free_no_clear(HASHMAP_BASE(h)); + } + + return NULL; +} + +void internal_hashmap_clear(HashmapBase *h) { + if (!h) + return; + + if (h->has_indirect) { + free(h->indirect.storage); + h->has_indirect = false; + } + + h->n_direct_entries = 0; + reset_direct_storage(h); + + if (h->type == HASHMAP_TYPE_ORDERED) { + OrderedHashmap *lh = (OrderedHashmap*) h; + lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL; + } +} + +void internal_hashmap_clear_free(HashmapBase *h) { + unsigned idx; + + if (!h) + return; + + for (idx = skip_free_buckets(h, 0); idx != IDX_NIL; + idx = skip_free_buckets(h, idx + 1)) + free(entry_value(h, bucket_at(h, idx))); + + internal_hashmap_clear(h); +} + +void hashmap_clear_free_free(Hashmap *h) { + unsigned idx; + + if (!h) + return; + + for (idx = skip_free_buckets(HASHMAP_BASE(h), 0); idx != IDX_NIL; + idx = skip_free_buckets(HASHMAP_BASE(h), idx + 1)) { + struct plain_hashmap_entry *e = plain_bucket_at(h, idx); + free((void*)e->b.key); + free(e->value); + } + + internal_hashmap_clear(HASHMAP_BASE(h)); +} + +static int resize_buckets(HashmapBase *h, unsigned entries_add); + +/* + * Finds an empty bucket to put an entry into, starting the scan at 'idx'. + * Performs Robin Hood swaps as it goes. The entry to put must be placed + * by the caller into swap slot IDX_PUT. + * If used for in-place resizing, may leave a displaced entry in swap slot + * IDX_PUT. Caller must rehash it next. + * Returns: true if it left a displaced entry to rehash next in IDX_PUT, + * false otherwise. + */ +static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx, + struct swap_entries *swap) { + dib_raw_t raw_dib, *dibs; + unsigned dib, distance; + +#ifdef ENABLE_DEBUG_HASHMAP + h->debug.put_count++; +#endif + + dibs = dib_raw_ptr(h); + + for (distance = 0; ; distance++) { + raw_dib = dibs[idx]; + if (raw_dib == DIB_RAW_FREE || raw_dib == DIB_RAW_REHASH) { + if (raw_dib == DIB_RAW_REHASH) + bucket_move_entry(h, swap, idx, IDX_TMP); + + if (h->has_indirect && h->indirect.idx_lowest_entry > idx) + h->indirect.idx_lowest_entry = idx; + + bucket_set_dib(h, idx, distance); + bucket_move_entry(h, swap, IDX_PUT, idx); + if (raw_dib == DIB_RAW_REHASH) { + bucket_move_entry(h, swap, IDX_TMP, IDX_PUT); + return true; + } + + return false; + } + + dib = bucket_calculate_dib(h, idx, raw_dib); + + if (dib < distance) { + /* Found a wealthier entry. Go Robin Hood! */ + bucket_set_dib(h, idx, distance); + + /* swap the entries */ + bucket_move_entry(h, swap, idx, IDX_TMP); + bucket_move_entry(h, swap, IDX_PUT, idx); + bucket_move_entry(h, swap, IDX_TMP, IDX_PUT); + + distance = dib; + } + + idx = next_idx(h, idx); + } +} + +/* + * Puts an entry into a hashmap, boldly - no check whether key already exists. + * The caller must place the entry (only its key and value, not link indexes) + * in swap slot IDX_PUT. + * Caller must ensure: the key does not exist yet in the hashmap. + * that resize is not needed if !may_resize. + * Returns: 1 if entry was put successfully. + * -ENOMEM if may_resize==true and resize failed with -ENOMEM. + * Cannot return -ENOMEM if !may_resize. + */ +static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx, + struct swap_entries *swap, bool may_resize) { + struct ordered_hashmap_entry *new_entry; + int r; + + assert(idx < n_buckets(h)); + + new_entry = bucket_at_swap(swap, IDX_PUT); + + if (may_resize) { + r = resize_buckets(h, 1); + if (r < 0) + return r; + if (r > 0) + idx = bucket_hash(h, new_entry->p.b.key); + } + assert(n_entries(h) < n_buckets(h)); + + if (h->type == HASHMAP_TYPE_ORDERED) { + OrderedHashmap *lh = (OrderedHashmap*) h; + + new_entry->iterate_next = IDX_NIL; + new_entry->iterate_previous = lh->iterate_list_tail; + + if (lh->iterate_list_tail != IDX_NIL) { + struct ordered_hashmap_entry *old_tail; + + old_tail = ordered_bucket_at(lh, lh->iterate_list_tail); + assert(old_tail->iterate_next == IDX_NIL); + old_tail->iterate_next = IDX_PUT; + } + + lh->iterate_list_tail = IDX_PUT; + if (lh->iterate_list_head == IDX_NIL) + lh->iterate_list_head = IDX_PUT; + } + + assert_se(hashmap_put_robin_hood(h, idx, swap) == false); + + n_entries_inc(h); +#ifdef ENABLE_DEBUG_HASHMAP + h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h)); +#endif + + return 1; +} +#define hashmap_put_boldly(h, idx, swap, may_resize) \ + hashmap_base_put_boldly(HASHMAP_BASE(h), idx, swap, may_resize) + +/* + * Returns 0 if resize is not needed. + * 1 if successfully resized. + * -ENOMEM on allocation failure. + */ +static int resize_buckets(HashmapBase *h, unsigned entries_add) { + struct swap_entries swap; + char *new_storage; + dib_raw_t *old_dibs, *new_dibs; + const struct hashmap_type_info *hi; + unsigned idx, optimal_idx; + unsigned old_n_buckets, new_n_buckets, n_rehashed, new_n_entries; + uint8_t new_shift; + bool rehash_next; + + assert(h); + + hi = &hashmap_type_info[h->type]; + new_n_entries = n_entries(h) + entries_add; + + /* overflow? */ + if (_unlikely_(new_n_entries < entries_add)) + return -ENOMEM; + + /* For direct storage we allow 100% load, because it's tiny. */ + if (!h->has_indirect && new_n_entries <= hi->n_direct_buckets) + return 0; + + /* + * Load factor = n/m = 1 - (1/INV_KEEP_FREE). + * From it follows: m = n + n/(INV_KEEP_FREE - 1) + */ + new_n_buckets = new_n_entries + new_n_entries / (INV_KEEP_FREE - 1); + /* overflow? */ + if (_unlikely_(new_n_buckets < new_n_entries)) + return -ENOMEM; + + if (_unlikely_(new_n_buckets > UINT_MAX / (hi->entry_size + sizeof(dib_raw_t)))) + return -ENOMEM; + + old_n_buckets = n_buckets(h); + + if (_likely_(new_n_buckets <= old_n_buckets)) + return 0; + + new_shift = log2u_round_up(MAX( + new_n_buckets * (hi->entry_size + sizeof(dib_raw_t)), + 2 * sizeof(struct direct_storage))); + + /* Realloc storage (buckets and DIB array). */ + new_storage = realloc(h->has_indirect ? h->indirect.storage : NULL, + 1U << new_shift); + if (!new_storage) + return -ENOMEM; + + /* Must upgrade direct to indirect storage. */ + if (!h->has_indirect) { + memcpy(new_storage, h->direct.storage, + old_n_buckets * (hi->entry_size + sizeof(dib_raw_t))); + h->indirect.n_entries = h->n_direct_entries; + h->indirect.idx_lowest_entry = 0; + h->n_direct_entries = 0; + } + + /* Get a new hash key. If we've just upgraded to indirect storage, + * allow reusing a previously generated key. It's still a different key + * from the shared one that we used for direct storage. */ + get_hash_key(h->indirect.hash_key, !h->has_indirect); + + h->has_indirect = true; + h->indirect.storage = new_storage; + h->indirect.n_buckets = (1U << new_shift) / + (hi->entry_size + sizeof(dib_raw_t)); + + old_dibs = (dib_raw_t*)(new_storage + hi->entry_size * old_n_buckets); + new_dibs = dib_raw_ptr(h); + + /* + * Move the DIB array to the new place, replacing valid DIB values with + * DIB_RAW_REHASH to indicate all of the used buckets need rehashing. + * Note: Overlap is not possible, because we have at least doubled the + * number of buckets and dib_raw_t is smaller than any entry type. + */ + for (idx = 0; idx < old_n_buckets; idx++) { + assert(old_dibs[idx] != DIB_RAW_REHASH); + new_dibs[idx] = old_dibs[idx] == DIB_RAW_FREE ? DIB_RAW_FREE + : DIB_RAW_REHASH; + } + + /* Zero the area of newly added entries (including the old DIB area) */ + memzero(bucket_at(h, old_n_buckets), + (n_buckets(h) - old_n_buckets) * hi->entry_size); + + /* The upper half of the new DIB array needs initialization */ + memset(&new_dibs[old_n_buckets], DIB_RAW_INIT, + (n_buckets(h) - old_n_buckets) * sizeof(dib_raw_t)); + + /* Rehash entries that need it */ + n_rehashed = 0; + for (idx = 0; idx < old_n_buckets; idx++) { + if (new_dibs[idx] != DIB_RAW_REHASH) + continue; + + optimal_idx = bucket_hash(h, bucket_at(h, idx)->key); + + /* + * Not much to do if by luck the entry hashes to its current + * location. Just set its DIB. + */ + if (optimal_idx == idx) { + new_dibs[idx] = 0; + n_rehashed++; + continue; + } + + new_dibs[idx] = DIB_RAW_FREE; + bucket_move_entry(h, &swap, idx, IDX_PUT); + /* bucket_move_entry does not clear the source */ + memzero(bucket_at(h, idx), hi->entry_size); + + do { + /* + * Find the new bucket for the current entry. This may make + * another entry homeless and load it into IDX_PUT. + */ + rehash_next = hashmap_put_robin_hood(h, optimal_idx, &swap); + n_rehashed++; + + /* Did the current entry displace another one? */ + if (rehash_next) + optimal_idx = bucket_hash(h, bucket_at_swap(&swap, IDX_PUT)->p.b.key); + } while (rehash_next); + } + + assert(n_rehashed == n_entries(h)); + + return 1; +} + +/* + * Finds an entry with a matching key + * Returns: index of the found entry, or IDX_NIL if not found. + */ +static unsigned base_bucket_scan(HashmapBase *h, unsigned idx, const void *key) { + struct hashmap_base_entry *e; + unsigned dib, distance; + dib_raw_t *dibs = dib_raw_ptr(h); + + assert(idx < n_buckets(h)); + + for (distance = 0; ; distance++) { + if (dibs[idx] == DIB_RAW_FREE) + return IDX_NIL; + + dib = bucket_calculate_dib(h, idx, dibs[idx]); + + if (dib < distance) + return IDX_NIL; + if (dib == distance) { + e = bucket_at(h, idx); + if (h->hash_ops->compare(e->key, key) == 0) + return idx; + } + + idx = next_idx(h, idx); + } +} +#define bucket_scan(h, idx, key) base_bucket_scan(HASHMAP_BASE(h), idx, key) + +int hashmap_put(Hashmap *h, const void *key, void *value) { + struct swap_entries swap; + struct plain_hashmap_entry *e; + unsigned hash, idx; + + assert(h); + + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx != IDX_NIL) { + e = plain_bucket_at(h, idx); + if (e->value == value) + return 0; + return -EEXIST; + } + + e = &bucket_at_swap(&swap, IDX_PUT)->p; + e->b.key = key; + e->value = value; + return hashmap_put_boldly(h, hash, &swap, true); +} + +int set_put(Set *s, const void *key) { + struct swap_entries swap; + struct hashmap_base_entry *e; + unsigned hash, idx; + + assert(s); + + hash = bucket_hash(s, key); + idx = bucket_scan(s, hash, key); + if (idx != IDX_NIL) + return 0; + + e = &bucket_at_swap(&swap, IDX_PUT)->p.b; + e->key = key; + return hashmap_put_boldly(s, hash, &swap, true); +} + +int hashmap_replace(Hashmap *h, const void *key, void *value) { + struct swap_entries swap; + struct plain_hashmap_entry *e; + unsigned hash, idx; + + assert(h); + + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx != IDX_NIL) { + e = plain_bucket_at(h, idx); +#ifdef ENABLE_DEBUG_HASHMAP + /* Although the key is equal, the key pointer may have changed, + * and this would break our assumption for iterating. So count + * this operation as incompatible with iteration. */ + if (e->b.key != key) { + h->b.debug.put_count++; + h->b.debug.rem_count++; + h->b.debug.last_rem_idx = idx; + } +#endif + e->b.key = key; + e->value = value; + return 0; + } + + e = &bucket_at_swap(&swap, IDX_PUT)->p; + e->b.key = key; + e->value = value; + return hashmap_put_boldly(h, hash, &swap, true); +} + +int hashmap_update(Hashmap *h, const void *key, void *value) { + struct plain_hashmap_entry *e; + unsigned hash, idx; + + assert(h); + + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx == IDX_NIL) + return -ENOENT; + + e = plain_bucket_at(h, idx); + e->value = value; + return 0; +} + +void *internal_hashmap_get(HashmapBase *h, const void *key) { + struct hashmap_base_entry *e; + unsigned hash, idx; + + if (!h) + return NULL; + + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx == IDX_NIL) + return NULL; + + e = bucket_at(h, idx); + return entry_value(h, e); +} + +void *hashmap_get2(Hashmap *h, const void *key, void **key2) { + struct plain_hashmap_entry *e; + unsigned hash, idx; + + if (!h) + return NULL; + + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx == IDX_NIL) + return NULL; + + e = plain_bucket_at(h, idx); + if (key2) + *key2 = (void*) e->b.key; + + return e->value; +} + +bool internal_hashmap_contains(HashmapBase *h, const void *key) { + unsigned hash; + + if (!h) + return false; + + hash = bucket_hash(h, key); + return bucket_scan(h, hash, key) != IDX_NIL; +} + +void *internal_hashmap_remove(HashmapBase *h, const void *key) { + struct hashmap_base_entry *e; + unsigned hash, idx; + void *data; + + if (!h) + return NULL; + + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx == IDX_NIL) + return NULL; + + e = bucket_at(h, idx); + data = entry_value(h, e); + remove_entry(h, idx); + + return data; +} + +void *hashmap_remove2(Hashmap *h, const void *key, void **rkey) { + struct plain_hashmap_entry *e; + unsigned hash, idx; + void *data; + + if (!h) { + if (rkey) + *rkey = NULL; + return NULL; + } + + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx == IDX_NIL) { + if (rkey) + *rkey = NULL; + return NULL; + } + + e = plain_bucket_at(h, idx); + data = e->value; + if (rkey) + *rkey = (void*) e->b.key; + + remove_entry(h, idx); + + return data; +} + +int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) { + struct swap_entries swap; + struct plain_hashmap_entry *e; + unsigned old_hash, new_hash, idx; + + if (!h) + return -ENOENT; + + old_hash = bucket_hash(h, old_key); + idx = bucket_scan(h, old_hash, old_key); + if (idx == IDX_NIL) + return -ENOENT; + + new_hash = bucket_hash(h, new_key); + if (bucket_scan(h, new_hash, new_key) != IDX_NIL) + return -EEXIST; + + remove_entry(h, idx); + + e = &bucket_at_swap(&swap, IDX_PUT)->p; + e->b.key = new_key; + e->value = value; + assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1); + + return 0; +} + +int set_remove_and_put(Set *s, const void *old_key, const void *new_key) { + struct swap_entries swap; + struct hashmap_base_entry *e; + unsigned old_hash, new_hash, idx; + + if (!s) + return -ENOENT; + + old_hash = bucket_hash(s, old_key); + idx = bucket_scan(s, old_hash, old_key); + if (idx == IDX_NIL) + return -ENOENT; + + new_hash = bucket_hash(s, new_key); + if (bucket_scan(s, new_hash, new_key) != IDX_NIL) + return -EEXIST; + + remove_entry(s, idx); + + e = &bucket_at_swap(&swap, IDX_PUT)->p.b; + e->key = new_key; + assert_se(hashmap_put_boldly(s, new_hash, &swap, false) == 1); + + return 0; +} + +int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value) { + struct swap_entries swap; + struct plain_hashmap_entry *e; + unsigned old_hash, new_hash, idx_old, idx_new; + + if (!h) + return -ENOENT; + + old_hash = bucket_hash(h, old_key); + idx_old = bucket_scan(h, old_hash, old_key); + if (idx_old == IDX_NIL) + return -ENOENT; + + old_key = bucket_at(HASHMAP_BASE(h), idx_old)->key; + + new_hash = bucket_hash(h, new_key); + idx_new = bucket_scan(h, new_hash, new_key); + if (idx_new != IDX_NIL) + if (idx_old != idx_new) { + remove_entry(h, idx_new); + /* Compensate for a possible backward shift. */ + if (old_key != bucket_at(HASHMAP_BASE(h), idx_old)->key) + idx_old = prev_idx(HASHMAP_BASE(h), idx_old); + assert(old_key == bucket_at(HASHMAP_BASE(h), idx_old)->key); + } + + remove_entry(h, idx_old); + + e = &bucket_at_swap(&swap, IDX_PUT)->p; + e->b.key = new_key; + e->value = value; + assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1); + + return 0; +} + +void *hashmap_remove_value(Hashmap *h, const void *key, void *value) { + struct plain_hashmap_entry *e; + unsigned hash, idx; + + if (!h) + return NULL; + + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx == IDX_NIL) + return NULL; + + e = plain_bucket_at(h, idx); + if (e->value != value) + return NULL; + + remove_entry(h, idx); + + return value; +} + +static unsigned find_first_entry(HashmapBase *h) { + Iterator i = ITERATOR_FIRST; + + if (!h || !n_entries(h)) + return IDX_NIL; + + return hashmap_iterate_entry(h, &i); +} + +void *internal_hashmap_first(HashmapBase *h) { + unsigned idx; + + idx = find_first_entry(h); + if (idx == IDX_NIL) + return NULL; + + return entry_value(h, bucket_at(h, idx)); +} + +void *internal_hashmap_first_key(HashmapBase *h) { + struct hashmap_base_entry *e; + unsigned idx; + + idx = find_first_entry(h); + if (idx == IDX_NIL) + return NULL; + + e = bucket_at(h, idx); + return (void*) e->key; +} + +void *internal_hashmap_steal_first(HashmapBase *h) { + struct hashmap_base_entry *e; + void *data; + unsigned idx; + + idx = find_first_entry(h); + if (idx == IDX_NIL) + return NULL; + + e = bucket_at(h, idx); + data = entry_value(h, e); + remove_entry(h, idx); + + return data; +} + +void *internal_hashmap_steal_first_key(HashmapBase *h) { + struct hashmap_base_entry *e; + void *key; + unsigned idx; + + idx = find_first_entry(h); + if (idx == IDX_NIL) + return NULL; + + e = bucket_at(h, idx); + key = (void*) e->key; + remove_entry(h, idx); + + return key; +} + +unsigned internal_hashmap_size(HashmapBase *h) { + + if (!h) + return 0; + + return n_entries(h); +} + +unsigned internal_hashmap_buckets(HashmapBase *h) { + + if (!h) + return 0; + + return n_buckets(h); +} + +int internal_hashmap_merge(Hashmap *h, Hashmap *other) { + Iterator i; + unsigned idx; + + assert(h); + + HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) { + struct plain_hashmap_entry *pe = plain_bucket_at(other, idx); + int r; + + r = hashmap_put(h, pe->b.key, pe->value); + if (r < 0 && r != -EEXIST) + return r; + } + + return 0; +} + +int set_merge(Set *s, Set *other) { + Iterator i; + unsigned idx; + + assert(s); + + HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) { + struct set_entry *se = set_bucket_at(other, idx); + int r; + + r = set_put(s, se->b.key); + if (r < 0) + return r; + } + + return 0; +} + +int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add) { + int r; + + assert(h); + + r = resize_buckets(h, entries_add); + if (r < 0) + return r; + + return 0; +} + +/* + * The same as hashmap_merge(), but every new item from other is moved to h. + * Keys already in h are skipped and stay in other. + * Returns: 0 on success. + * -ENOMEM on alloc failure, in which case no move has been done. + */ +int internal_hashmap_move(HashmapBase *h, HashmapBase *other) { + struct swap_entries swap; + struct hashmap_base_entry *e, *n; + Iterator i; + unsigned idx; + int r; + + assert(h); + + if (!other) + return 0; + + assert(other->type == h->type); + + /* + * This reserves buckets for the worst case, where none of other's + * entries are yet present in h. This is preferable to risking + * an allocation failure in the middle of the moving and having to + * rollback or return a partial result. + */ + r = resize_buckets(h, n_entries(other)); + if (r < 0) + return r; + + HASHMAP_FOREACH_IDX(idx, other, i) { + unsigned h_hash; + + e = bucket_at(other, idx); + h_hash = bucket_hash(h, e->key); + if (bucket_scan(h, h_hash, e->key) != IDX_NIL) + continue; + + n = &bucket_at_swap(&swap, IDX_PUT)->p.b; + n->key = e->key; + if (h->type != HASHMAP_TYPE_SET) + ((struct plain_hashmap_entry*) n)->value = + ((struct plain_hashmap_entry*) e)->value; + assert_se(hashmap_put_boldly(h, h_hash, &swap, false) == 1); + + remove_entry(other, idx); + } + + return 0; +} + +int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) { + struct swap_entries swap; + unsigned h_hash, other_hash, idx; + struct hashmap_base_entry *e, *n; + int r; + + assert(h); + + h_hash = bucket_hash(h, key); + if (bucket_scan(h, h_hash, key) != IDX_NIL) + return -EEXIST; + + if (!other) + return -ENOENT; + + assert(other->type == h->type); + + other_hash = bucket_hash(other, key); + idx = bucket_scan(other, other_hash, key); + if (idx == IDX_NIL) + return -ENOENT; + + e = bucket_at(other, idx); + + n = &bucket_at_swap(&swap, IDX_PUT)->p.b; + n->key = e->key; + if (h->type != HASHMAP_TYPE_SET) + ((struct plain_hashmap_entry*) n)->value = + ((struct plain_hashmap_entry*) e)->value; + r = hashmap_put_boldly(h, h_hash, &swap, true); + if (r < 0) + return r; + + remove_entry(other, idx); + return 0; +} + +HashmapBase *internal_hashmap_copy(HashmapBase *h) { + HashmapBase *copy; + int r; + + assert(h); + + copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_SRC_ARGS); + if (!copy) + return NULL; + + switch (h->type) { + case HASHMAP_TYPE_PLAIN: + case HASHMAP_TYPE_ORDERED: + r = hashmap_merge((Hashmap*)copy, (Hashmap*)h); + break; + case HASHMAP_TYPE_SET: + r = set_merge((Set*)copy, (Set*)h); + break; + default: + assert_not_reached("Unknown hashmap type"); + } + + if (r < 0) { + internal_hashmap_free(copy); + return NULL; + } + + return copy; +} + +char **internal_hashmap_get_strv(HashmapBase *h) { + char **sv; + Iterator i; + unsigned idx, n; + + sv = new(char*, n_entries(h)+1); + if (!sv) + return NULL; + + n = 0; + HASHMAP_FOREACH_IDX(idx, h, i) + sv[n++] = entry_value(h, bucket_at(h, idx)); + sv[n] = NULL; + + return sv; +} + +void *ordered_hashmap_next(OrderedHashmap *h, const void *key) { + struct ordered_hashmap_entry *e; + unsigned hash, idx; + + if (!h) + return NULL; + + hash = bucket_hash(h, key); + idx = bucket_scan(h, hash, key); + if (idx == IDX_NIL) + return NULL; + + e = ordered_bucket_at(h, idx); + if (e->iterate_next == IDX_NIL) + return NULL; + return ordered_bucket_at(h, e->iterate_next)->p.value; +} + +int set_consume(Set *s, void *value) { + int r; + + r = set_put(s, value); + if (r <= 0) + free(value); + + return r; +} + +int set_put_strdup(Set *s, const char *p) { + char *c; + int r; + + assert(s); + assert(p); + + c = strdup(p); + if (!c) + return -ENOMEM; + + r = set_consume(s, c); + if (r == -EEXIST) + return 0; + + return r; +} + +int set_put_strdupv(Set *s, char **l) { + int n = 0, r; + char **i; + + STRV_FOREACH(i, l) { + r = set_put_strdup(s, *i); + if (r < 0) + return r; + + n += r; + } + + return n; +} diff --git a/src/systemd/src/basic/hashmap.h b/src/systemd/src/basic/hashmap.h new file mode 100644 index 00000000..0485e1d4 --- /dev/null +++ b/src/systemd/src/basic/hashmap.h @@ -0,0 +1,417 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2014 Michal Schmidt + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include + +#include "macro.h" +#include "siphash24.h" +#include "util.h" + +/* + * A hash table implementation. As a minor optimization a NULL hashmap object + * will be treated as empty hashmap for all read operations. That way it is not + * necessary to instantiate an object for each Hashmap use. + * + * If ENABLE_DEBUG_HASHMAP is defined (by configuring with --enable-debug=hashmap), + * the implemention will: + * - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py) + * - perform extra checks for invalid use of iterators + */ + +#define HASH_KEY_SIZE 16 + +/* The base type for all hashmap and set types. Many functions in the + * implementation take (HashmapBase*) parameters and are run-time polymorphic, + * though the API is not meant to be polymorphic (do not call functions + * internal_*() directly). */ +typedef struct HashmapBase HashmapBase; + +/* Specific hashmap/set types */ +typedef struct Hashmap Hashmap; /* Maps keys to values */ +typedef struct OrderedHashmap OrderedHashmap; /* Like Hashmap, but also remembers entry insertion order */ +typedef struct Set Set; /* Stores just keys */ + +/* Ideally the Iterator would be an opaque struct, but it is instantiated + * by hashmap users, so the definition has to be here. Do not use its fields + * directly. */ +typedef struct { + unsigned idx; /* index of an entry to be iterated next */ + const void *next_key; /* expected value of that entry's key pointer */ +#ifdef ENABLE_DEBUG_HASHMAP + unsigned put_count; /* hashmap's put_count recorded at start of iteration */ + unsigned rem_count; /* hashmap's rem_count in previous iteration */ + unsigned prev_idx; /* idx in previous iteration */ +#endif +} Iterator; + +#define _IDX_ITERATOR_FIRST (UINT_MAX - 1) +#define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL }) + +typedef void (*hash_func_t)(const void *p, struct siphash *state); +typedef int (*compare_func_t)(const void *a, const void *b); + +struct hash_ops { + hash_func_t hash; + compare_func_t compare; +}; + +void string_hash_func(const void *p, struct siphash *state); +int string_compare_func(const void *a, const void *b) _pure_; +extern const struct hash_ops string_hash_ops; + +/* This will compare the passed pointers directly, and will not + * dereference them. This is hence not useful for strings or + * suchlike. */ +void trivial_hash_func(const void *p, struct siphash *state); +int trivial_compare_func(const void *a, const void *b) _const_; +extern const struct hash_ops trivial_hash_ops; + +/* 32bit values we can always just embedd in the pointer itself, but + * in order to support 32bit archs we need store 64bit values + * indirectly, since they don't fit in a pointer. */ +void uint64_hash_func(const void *p, struct siphash *state); +int uint64_compare_func(const void *a, const void *b) _pure_; +extern const struct hash_ops uint64_hash_ops; + +/* On some archs dev_t is 32bit, and on others 64bit. And sometimes + * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */ +#if SIZEOF_DEV_T != 8 +void devt_hash_func(const void *p, struct siphash *state) _pure_; +int devt_compare_func(const void *a, const void *b) _pure_; +extern const struct hash_ops devt_hash_ops = { + .hash = devt_hash_func, + .compare = devt_compare_func +}; +#else +#define devt_hash_func uint64_hash_func +#define devt_compare_func uint64_compare_func +#define devt_hash_ops uint64_hash_ops +#endif + +/* Macros for type checking */ +#define PTR_COMPATIBLE_WITH_HASHMAP_BASE(h) \ + (__builtin_types_compatible_p(typeof(h), HashmapBase*) || \ + __builtin_types_compatible_p(typeof(h), Hashmap*) || \ + __builtin_types_compatible_p(typeof(h), OrderedHashmap*) || \ + __builtin_types_compatible_p(typeof(h), Set*)) + +#define PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h) \ + (__builtin_types_compatible_p(typeof(h), Hashmap*) || \ + __builtin_types_compatible_p(typeof(h), OrderedHashmap*)) \ + +#define HASHMAP_BASE(h) \ + __builtin_choose_expr(PTR_COMPATIBLE_WITH_HASHMAP_BASE(h), \ + (HashmapBase*)(h), \ + (void)0) + +#define PLAIN_HASHMAP(h) \ + __builtin_choose_expr(PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h), \ + (Hashmap*)(h), \ + (void)0) + +#ifdef ENABLE_DEBUG_HASHMAP +# define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line +# define HASHMAP_DEBUG_SRC_ARGS , __func__, __FILE__, __LINE__ +# define HASHMAP_DEBUG_PASS_ARGS , func, file, line +#else +# define HASHMAP_DEBUG_PARAMS +# define HASHMAP_DEBUG_SRC_ARGS +# define HASHMAP_DEBUG_PASS_ARGS +#endif + +Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +#define hashmap_new(ops) internal_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) +#define ordered_hashmap_new(ops) internal_ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) + +HashmapBase *internal_hashmap_free(HashmapBase *h); +static inline Hashmap *hashmap_free(Hashmap *h) { + return (void*)internal_hashmap_free(HASHMAP_BASE(h)); +} +static inline OrderedHashmap *ordered_hashmap_free(OrderedHashmap *h) { + return (void*)internal_hashmap_free(HASHMAP_BASE(h)); +} + +HashmapBase *internal_hashmap_free_free(HashmapBase *h); +static inline Hashmap *hashmap_free_free(Hashmap *h) { + return (void*)internal_hashmap_free_free(HASHMAP_BASE(h)); +} +static inline OrderedHashmap *ordered_hashmap_free_free(OrderedHashmap *h) { + return (void*)internal_hashmap_free_free(HASHMAP_BASE(h)); +} + +Hashmap *hashmap_free_free_free(Hashmap *h); +static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h) { + return (void*)hashmap_free_free_free(PLAIN_HASHMAP(h)); +} + +HashmapBase *internal_hashmap_copy(HashmapBase *h); +static inline Hashmap *hashmap_copy(Hashmap *h) { + return (Hashmap*) internal_hashmap_copy(HASHMAP_BASE(h)); +} +static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) { + return (OrderedHashmap*) internal_hashmap_copy(HASHMAP_BASE(h)); +} + +int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +#define hashmap_ensure_allocated(h, ops) internal_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) +#define ordered_hashmap_ensure_allocated(h, ops) internal_ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) + +int hashmap_put(Hashmap *h, const void *key, void *value); +static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *value) { + return hashmap_put(PLAIN_HASHMAP(h), key, value); +} + +int hashmap_update(Hashmap *h, const void *key, void *value); +static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) { + return hashmap_update(PLAIN_HASHMAP(h), key, value); +} + +int hashmap_replace(Hashmap *h, const void *key, void *value); +static inline int ordered_hashmap_replace(OrderedHashmap *h, const void *key, void *value) { + return hashmap_replace(PLAIN_HASHMAP(h), key, value); +} + +void *internal_hashmap_get(HashmapBase *h, const void *key); +static inline void *hashmap_get(Hashmap *h, const void *key) { + return internal_hashmap_get(HASHMAP_BASE(h), key); +} +static inline void *ordered_hashmap_get(OrderedHashmap *h, const void *key) { + return internal_hashmap_get(HASHMAP_BASE(h), key); +} + +void *hashmap_get2(Hashmap *h, const void *key, void **rkey); +static inline void *ordered_hashmap_get2(OrderedHashmap *h, const void *key, void **rkey) { + return hashmap_get2(PLAIN_HASHMAP(h), key, rkey); +} + +bool internal_hashmap_contains(HashmapBase *h, const void *key); +static inline bool hashmap_contains(Hashmap *h, const void *key) { + return internal_hashmap_contains(HASHMAP_BASE(h), key); +} +static inline bool ordered_hashmap_contains(OrderedHashmap *h, const void *key) { + return internal_hashmap_contains(HASHMAP_BASE(h), key); +} + +void *internal_hashmap_remove(HashmapBase *h, const void *key); +static inline void *hashmap_remove(Hashmap *h, const void *key) { + return internal_hashmap_remove(HASHMAP_BASE(h), key); +} +static inline void *ordered_hashmap_remove(OrderedHashmap *h, const void *key) { + return internal_hashmap_remove(HASHMAP_BASE(h), key); +} + +void *hashmap_remove2(Hashmap *h, const void *key, void **rkey); +static inline void *ordered_hashmap_remove2(OrderedHashmap *h, const void *key, void **rkey) { + return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey); +} + +void *hashmap_remove_value(Hashmap *h, const void *key, void *value); +static inline void *ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) { + return hashmap_remove_value(PLAIN_HASHMAP(h), key, value); +} + +int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value); +static inline int ordered_hashmap_remove_and_put(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) { + return hashmap_remove_and_put(PLAIN_HASHMAP(h), old_key, new_key, value); +} + +int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value); +static inline int ordered_hashmap_remove_and_replace(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) { + return hashmap_remove_and_replace(PLAIN_HASHMAP(h), old_key, new_key, value); +} + +/* Since merging data from a OrderedHashmap into a Hashmap or vice-versa + * should just work, allow this by having looser type-checking here. */ +int internal_hashmap_merge(Hashmap *h, Hashmap *other); +#define hashmap_merge(h, other) internal_hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other)) +#define ordered_hashmap_merge(h, other) hashmap_merge(h, other) + +int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add); +static inline int hashmap_reserve(Hashmap *h, unsigned entries_add) { + return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); +} +static inline int ordered_hashmap_reserve(OrderedHashmap *h, unsigned entries_add) { + return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); +} + +int internal_hashmap_move(HashmapBase *h, HashmapBase *other); +/* Unlike hashmap_merge, hashmap_move does not allow mixing the types. */ +static inline int hashmap_move(Hashmap *h, Hashmap *other) { + return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other)); +} +static inline int ordered_hashmap_move(OrderedHashmap *h, OrderedHashmap *other) { + return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other)); +} + +int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key); +static inline int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) { + return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key); +} +static inline int ordered_hashmap_move_one(OrderedHashmap *h, OrderedHashmap *other, const void *key) { + return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key); +} + +unsigned internal_hashmap_size(HashmapBase *h) _pure_; +static inline unsigned hashmap_size(Hashmap *h) { + return internal_hashmap_size(HASHMAP_BASE(h)); +} +static inline unsigned ordered_hashmap_size(OrderedHashmap *h) { + return internal_hashmap_size(HASHMAP_BASE(h)); +} + +static inline bool hashmap_isempty(Hashmap *h) { + return hashmap_size(h) == 0; +} +static inline bool ordered_hashmap_isempty(OrderedHashmap *h) { + return ordered_hashmap_size(h) == 0; +} + +unsigned internal_hashmap_buckets(HashmapBase *h) _pure_; +static inline unsigned hashmap_buckets(Hashmap *h) { + return internal_hashmap_buckets(HASHMAP_BASE(h)); +} +static inline unsigned ordered_hashmap_buckets(OrderedHashmap *h) { + return internal_hashmap_buckets(HASHMAP_BASE(h)); +} + +bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key); +static inline bool hashmap_iterate(Hashmap *h, Iterator *i, void **value, const void **key) { + return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key); +} +static inline bool ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, void **value, const void **key) { + return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key); +} + +void internal_hashmap_clear(HashmapBase *h); +static inline void hashmap_clear(Hashmap *h) { + internal_hashmap_clear(HASHMAP_BASE(h)); +} +static inline void ordered_hashmap_clear(OrderedHashmap *h) { + internal_hashmap_clear(HASHMAP_BASE(h)); +} + +void internal_hashmap_clear_free(HashmapBase *h); +static inline void hashmap_clear_free(Hashmap *h) { + internal_hashmap_clear_free(HASHMAP_BASE(h)); +} +static inline void ordered_hashmap_clear_free(OrderedHashmap *h) { + internal_hashmap_clear_free(HASHMAP_BASE(h)); +} + +void hashmap_clear_free_free(Hashmap *h); +static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) { + hashmap_clear_free_free(PLAIN_HASHMAP(h)); +} + +/* + * Note about all *_first*() functions + * + * For plain Hashmaps and Sets the order of entries is undefined. + * The functions find whatever entry is first in the implementation + * internal order. + * + * Only for OrderedHashmaps the order is well defined and finding + * the first entry is O(1). + */ + +void *internal_hashmap_steal_first(HashmapBase *h); +static inline void *hashmap_steal_first(Hashmap *h) { + return internal_hashmap_steal_first(HASHMAP_BASE(h)); +} +static inline void *ordered_hashmap_steal_first(OrderedHashmap *h) { + return internal_hashmap_steal_first(HASHMAP_BASE(h)); +} + +void *internal_hashmap_steal_first_key(HashmapBase *h); +static inline void *hashmap_steal_first_key(Hashmap *h) { + return internal_hashmap_steal_first_key(HASHMAP_BASE(h)); +} +static inline void *ordered_hashmap_steal_first_key(OrderedHashmap *h) { + return internal_hashmap_steal_first_key(HASHMAP_BASE(h)); +} + +void *internal_hashmap_first_key(HashmapBase *h) _pure_; +static inline void *hashmap_first_key(Hashmap *h) { + return internal_hashmap_first_key(HASHMAP_BASE(h)); +} +static inline void *ordered_hashmap_first_key(OrderedHashmap *h) { + return internal_hashmap_first_key(HASHMAP_BASE(h)); +} + +void *internal_hashmap_first(HashmapBase *h) _pure_; +static inline void *hashmap_first(Hashmap *h) { + return internal_hashmap_first(HASHMAP_BASE(h)); +} +static inline void *ordered_hashmap_first(OrderedHashmap *h) { + return internal_hashmap_first(HASHMAP_BASE(h)); +} + +/* no hashmap_next */ +void *ordered_hashmap_next(OrderedHashmap *h, const void *key); + +char **internal_hashmap_get_strv(HashmapBase *h); +static inline char **hashmap_get_strv(Hashmap *h) { + return internal_hashmap_get_strv(HASHMAP_BASE(h)); +} +static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) { + return internal_hashmap_get_strv(HASHMAP_BASE(h)); +} + +/* + * Hashmaps are iterated in unpredictable order. + * OrderedHashmaps are an exception to this. They are iterated in the order + * the entries were inserted. + * It is safe to remove the current entry. + */ +#define HASHMAP_FOREACH(e, h, i) \ + for ((i) = ITERATOR_FIRST; hashmap_iterate((h), &(i), (void**)&(e), NULL); ) + +#define ORDERED_HASHMAP_FOREACH(e, h, i) \ + for ((i) = ITERATOR_FIRST; ordered_hashmap_iterate((h), &(i), (void**)&(e), NULL); ) + +#define HASHMAP_FOREACH_KEY(e, k, h, i) \ + for ((i) = ITERATOR_FIRST; hashmap_iterate((h), &(i), (void**)&(e), (const void**) &(k)); ) + +#define ORDERED_HASHMAP_FOREACH_KEY(e, k, h, i) \ + for ((i) = ITERATOR_FIRST; ordered_hashmap_iterate((h), &(i), (void**)&(e), (const void**) &(k)); ) + +DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free); + +#define _cleanup_hashmap_free_ _cleanup_(hashmap_freep) +#define _cleanup_hashmap_free_free_ _cleanup_(hashmap_free_freep) +#define _cleanup_hashmap_free_free_free_ _cleanup_(hashmap_free_free_freep) +#define _cleanup_ordered_hashmap_free_ _cleanup_(ordered_hashmap_freep) +#define _cleanup_ordered_hashmap_free_free_ _cleanup_(ordered_hashmap_free_freep) +#define _cleanup_ordered_hashmap_free_free_free_ _cleanup_(ordered_hashmap_free_free_freep) diff --git a/src/systemd/src/basic/hexdecoct.c b/src/systemd/src/basic/hexdecoct.c new file mode 100644 index 00000000..1f257bd5 --- /dev/null +++ b/src/systemd/src/basic/hexdecoct.c @@ -0,0 +1,702 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "alloc-util.h" +#include "hexdecoct.h" +#include "macro.h" + +char octchar(int x) { + return '0' + (x & 7); +} + +int unoctchar(char c) { + + if (c >= '0' && c <= '7') + return c - '0'; + + return -EINVAL; +} + +char decchar(int x) { + return '0' + (x % 10); +} + +int undecchar(char c) { + + if (c >= '0' && c <= '9') + return c - '0'; + + return -EINVAL; +} + +char hexchar(int x) { + static const char table[16] = "0123456789abcdef"; + + return table[x & 15]; +} + +int unhexchar(char c) { + + if (c >= '0' && c <= '9') + return c - '0'; + + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + + return -EINVAL; +} + +char *hexmem(const void *p, size_t l) { + char *r, *z; + const uint8_t *x; + + z = r = malloc(l * 2 + 1); + if (!r) + return NULL; + + for (x = p; x < (const uint8_t*) p + l; x++) { + *(z++) = hexchar(*x >> 4); + *(z++) = hexchar(*x & 15); + } + + *z = 0; + return r; +} + +int unhexmem(const char *p, size_t l, void **mem, size_t *len) { + _cleanup_free_ uint8_t *r = NULL; + uint8_t *z; + const char *x; + + assert(mem); + assert(len); + assert(p); + + z = r = malloc((l + 1) / 2 + 1); + if (!r) + return -ENOMEM; + + for (x = p; x < p + l; x += 2) { + int a, b; + + a = unhexchar(x[0]); + if (a < 0) + return a; + else if (x+1 < p + l) { + b = unhexchar(x[1]); + if (b < 0) + return b; + } else + b = 0; + + *(z++) = (uint8_t) a << 4 | (uint8_t) b; + } + + *z = 0; + + *mem = r; + r = NULL; + *len = (l + 1) / 2; + + return 0; +} + +/* https://tools.ietf.org/html/rfc4648#section-6 + * Notice that base32hex differs from base32 in the alphabet it uses. + * The distinction is that the base32hex representation preserves the + * order of the underlying data when compared as bytestrings, this is + * useful when representing NSEC3 hashes, as one can then verify the + * order of hashes directly from their representation. */ +char base32hexchar(int x) { + static const char table[32] = "0123456789" + "ABCDEFGHIJKLMNOPQRSTUV"; + + return table[x & 31]; +} + +int unbase32hexchar(char c) { + unsigned offset; + + if (c >= '0' && c <= '9') + return c - '0'; + + offset = '9' - '0' + 1; + + if (c >= 'A' && c <= 'V') + return c - 'A' + offset; + + return -EINVAL; +} + +char *base32hexmem(const void *p, size_t l, bool padding) { + char *r, *z; + const uint8_t *x; + size_t len; + + if (padding) + /* five input bytes makes eight output bytes, padding is added so we must round up */ + len = 8 * (l + 4) / 5; + else { + /* same, but round down as there is no padding */ + len = 8 * l / 5; + + switch (l % 5) { + case 4: + len += 7; + break; + case 3: + len += 5; + break; + case 2: + len += 4; + break; + case 1: + len += 2; + break; + } + } + + z = r = malloc(len + 1); + if (!r) + return NULL; + + for (x = p; x < (const uint8_t*) p + (l / 5) * 5; x += 5) { + /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ + x[3] == QQQQQQQQ; x[4] == WWWWWWWW */ + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ + *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */ + *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */ + *(z++) = base32hexchar((x[3] & 3) << 3 | x[4] >> 5); /* 000QQWWW */ + *(z++) = base32hexchar((x[4] & 31)); /* 000WWWWW */ + } + + switch (l % 5) { + case 4: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ + *(z++) = base32hexchar((x[2] & 15) << 1 | x[3] >> 7); /* 000ZZZZQ */ + *(z++) = base32hexchar((x[3] & 127) >> 2); /* 000QQQQQ */ + *(z++) = base32hexchar((x[3] & 3) << 3); /* 000QQ000 */ + if (padding) + *(z++) = '='; + + break; + + case 3: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4 | x[2] >> 4); /* 000YZZZZ */ + *(z++) = base32hexchar((x[2] & 15) << 1); /* 000ZZZZ0 */ + if (padding) { + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + } + + break; + + case 2: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2 | x[1] >> 6); /* 000XXXYY */ + *(z++) = base32hexchar((x[1] & 63) >> 1); /* 000YYYYY */ + *(z++) = base32hexchar((x[1] & 1) << 4); /* 000Y0000 */ + if (padding) { + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + } + + break; + + case 1: + *(z++) = base32hexchar(x[0] >> 3); /* 000XXXXX */ + *(z++) = base32hexchar((x[0] & 7) << 2); /* 000XXX00 */ + if (padding) { + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + *(z++) = '='; + } + + break; + } + + *z = 0; + return r; +} + +int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_len) { + _cleanup_free_ uint8_t *r = NULL; + int a, b, c, d, e, f, g, h; + uint8_t *z; + const char *x; + size_t len; + unsigned pad = 0; + + assert(p); + + /* padding ensures any base32hex input has input divisible by 8 */ + if (padding && l % 8 != 0) + return -EINVAL; + + if (padding) { + /* strip the padding */ + while (l > 0 && p[l - 1] == '=' && pad < 7) { + pad ++; + l --; + } + } + + /* a group of eight input bytes needs five output bytes, in case of + padding we need to add some extra bytes */ + len = (l / 8) * 5; + + switch (l % 8) { + case 7: + len += 4; + break; + case 5: + len += 3; + break; + case 4: + len += 2; + break; + case 2: + len += 1; + break; + case 0: + break; + default: + return -EINVAL; + } + + z = r = malloc(len + 1); + if (!r) + return -ENOMEM; + + for (x = p; x < p + (l / 8) * 8; x += 8) { + /* a == 000XXXXX; b == 000YYYYY; c == 000ZZZZZ; d == 000WWWWW + e == 000SSSSS; f == 000QQQQQ; g == 000VVVVV; h == 000RRRRR */ + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + e = unbase32hexchar(x[4]); + if (e < 0) + return -EINVAL; + + f = unbase32hexchar(x[5]); + if (f < 0) + return -EINVAL; + + g = unbase32hexchar(x[6]); + if (g < 0) + return -EINVAL; + + h = unbase32hexchar(x[7]); + if (h < 0) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ + *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */ + *(z++) = (uint8_t) g << 5 | (uint8_t) h; /* VVVRRRRR */ + } + + switch (l % 8) { + case 7: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + e = unbase32hexchar(x[4]); + if (e < 0) + return -EINVAL; + + f = unbase32hexchar(x[5]); + if (f < 0) + return -EINVAL; + + g = unbase32hexchar(x[6]); + if (g < 0) + return -EINVAL; + + /* g == 000VV000 */ + if (g & 7) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ + *(z++) = (uint8_t) e << 7 | (uint8_t) f << 2 | (uint8_t) g >> 3; /* SQQQQQVV */ + + break; + case 5: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + e = unbase32hexchar(x[4]); + if (e < 0) + return -EINVAL; + + /* e == 000SSSS0 */ + if (e & 1) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + *(z++) = (uint8_t) d << 4 | (uint8_t) e >> 1; /* WWWWSSSS */ + + break; + case 4: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase32hexchar(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase32hexchar(x[3]); + if (d < 0) + return -EINVAL; + + /* d == 000W0000 */ + if (d & 15) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + *(z++) = (uint8_t) b << 6 | (uint8_t) c << 1 | (uint8_t) d >> 4; /* YYZZZZZW */ + + break; + case 2: + a = unbase32hexchar(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase32hexchar(x[1]); + if (b < 0) + return -EINVAL; + + /* b == 000YYY00 */ + if (b & 3) + return -EINVAL; + + *(z++) = (uint8_t) a << 3 | (uint8_t) b >> 2; /* XXXXXYYY */ + + break; + case 0: + break; + default: + return -EINVAL; + } + + *z = 0; + + *mem = r; + r = NULL; + *_len = len; + + return 0; +} + +/* https://tools.ietf.org/html/rfc4648#section-4 */ +char base64char(int x) { + static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + return table[x & 63]; +} + +int unbase64char(char c) { + unsigned offset; + + if (c >= 'A' && c <= 'Z') + return c - 'A'; + + offset = 'Z' - 'A' + 1; + + if (c >= 'a' && c <= 'z') + return c - 'a' + offset; + + offset += 'z' - 'a' + 1; + + if (c >= '0' && c <= '9') + return c - '0' + offset; + + offset += '9' - '0' + 1; + + if (c == '+') + return offset; + + offset ++; + + if (c == '/') + return offset; + + return -EINVAL; +} + +char *base64mem(const void *p, size_t l) { + char *r, *z; + const uint8_t *x; + + /* three input bytes makes four output bytes, padding is added so we must round up */ + z = r = malloc(4 * (l + 2) / 3 + 1); + if (!r) + return NULL; + + for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) { + /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */ + *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ + *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ + *(z++) = base64char((x[1] & 15) << 2 | x[2] >> 6); /* 00YYYYZZ */ + *(z++) = base64char(x[2] & 63); /* 00ZZZZZZ */ + } + + switch (l % 3) { + case 2: + *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ + *(z++) = base64char((x[0] & 3) << 4 | x[1] >> 4); /* 00XXYYYY */ + *(z++) = base64char((x[1] & 15) << 2); /* 00YYYY00 */ + *(z++) = '='; + + break; + case 1: + *(z++) = base64char(x[0] >> 2); /* 00XXXXXX */ + *(z++) = base64char((x[0] & 3) << 4); /* 00XX0000 */ + *(z++) = '='; + *(z++) = '='; + + break; + } + + *z = 0; + return r; +} + +int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) { + _cleanup_free_ uint8_t *r = NULL; + int a, b, c, d; + uint8_t *z; + const char *x; + size_t len; + + assert(p); + + /* padding ensures any base63 input has input divisible by 4 */ + if (l % 4 != 0) + return -EINVAL; + + /* strip the padding */ + if (l > 0 && p[l - 1] == '=') + l --; + if (l > 0 && p[l - 1] == '=') + l --; + + /* a group of four input bytes needs three output bytes, in case of + padding we need to add two or three extra bytes */ + len = (l / 4) * 3 + (l % 4 ? (l % 4) - 1 : 0); + + z = r = malloc(len + 1); + if (!r) + return -ENOMEM; + + for (x = p; x < p + (l / 4) * 4; x += 4) { + /* a == 00XXXXXX; b == 00YYYYYY; c == 00ZZZZZZ; d == 00WWWWWW */ + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase64char(x[2]); + if (c < 0) + return -EINVAL; + + d = unbase64char(x[3]); + if (d < 0) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */ + } + + switch (l % 4) { + case 3: + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; + + c = unbase64char(x[2]); + if (c < 0) + return -EINVAL; + + /* c == 00ZZZZ00 */ + if (c & 3) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + + break; + case 2: + a = unbase64char(x[0]); + if (a < 0) + return -EINVAL; + + b = unbase64char(x[1]); + if (b < 0) + return -EINVAL; + + /* b == 00YY0000 */ + if (b & 15) + return -EINVAL; + + *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */ + + break; + case 0: + + break; + default: + return -EINVAL; + } + + *z = 0; + + *mem = r; + r = NULL; + *_len = len; + + return 0; +} + +void hexdump(FILE *f, const void *p, size_t s) { + const uint8_t *b = p; + unsigned n = 0; + + assert(s == 0 || b); + + while (s > 0) { + size_t i; + + fprintf(f, "%04x ", n); + + for (i = 0; i < 16; i++) { + + if (i >= s) + fputs(" ", f); + else + fprintf(f, "%02x ", b[i]); + + if (i == 7) + fputc(' ', f); + } + + fputc(' ', f); + + for (i = 0; i < 16; i++) { + + if (i >= s) + fputc(' ', f); + else + fputc(isprint(b[i]) ? (char) b[i] : '.', f); + } + + fputc('\n', f); + + if (s < 16) + break; + + n += 16; + b += 16; + s -= 16; + } +} diff --git a/src/systemd/src/basic/hexdecoct.h b/src/systemd/src/basic/hexdecoct.h new file mode 100644 index 00000000..ec4115f2 --- /dev/null +++ b/src/systemd/src/basic/hexdecoct.h @@ -0,0 +1,57 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "macro.h" + +char octchar(int x) _const_; +int unoctchar(char c) _const_; + +char decchar(int x) _const_; +int undecchar(char c) _const_; + +char hexchar(int x) _const_; +int unhexchar(char c) _const_; + +char *hexmem(const void *p, size_t l); +int unhexmem(const char *p, size_t l, void **mem, size_t *len); + +char base32hexchar(int x) _const_; +int unbase32hexchar(char c) _const_; + +char base64char(int x) _const_; +int unbase64char(char c) _const_; + +char *base32hexmem(const void *p, size_t l, bool padding); +int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len); + +char *base64mem(const void *p, size_t l); +int unbase64mem(const char *p, size_t l, void **mem, size_t *len); + +void hexdump(FILE *f, const void *p, size_t s); diff --git a/src/systemd/src/basic/hostname-util.c b/src/systemd/src/basic/hostname-util.c new file mode 100644 index 00000000..50f81925 --- /dev/null +++ b/src/systemd/src/basic/hostname-util.c @@ -0,0 +1,230 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2015 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "fd-util.h" +#include "fileio.h" +#include "hostname-util.h" +#include "macro.h" +#include "string-util.h" + +bool hostname_is_set(void) { + struct utsname u; + + assert_se(uname(&u) >= 0); + + if (isempty(u.nodename)) + return false; + + /* This is the built-in kernel default host name */ + if (streq(u.nodename, "(none)")) + return false; + + return true; +} + +char* gethostname_malloc(void) { + struct utsname u; + + assert_se(uname(&u) >= 0); + + if (isempty(u.nodename) || streq(u.nodename, "(none)")) + return strdup(u.sysname); + + return strdup(u.nodename); +} + +static bool hostname_valid_char(char c) { + return + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '-' || + c == '_' || + c == '.'; +} + +/** + * Check if s looks like a valid host name or FQDN. This does not do + * full DNS validation, but only checks if the name is composed of + * allowed characters and the length is not above the maximum allowed + * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if + * allow_trailing_dot is true and at least two components are present + * in the name. Note that due to the restricted charset and length + * this call is substantially more conservative than + * dns_name_is_valid(). + */ +bool hostname_is_valid(const char *s, bool allow_trailing_dot) { + unsigned n_dots = 0; + const char *p; + bool dot; + + if (isempty(s)) + return false; + + /* Doesn't accept empty hostnames, hostnames with + * leading dots, and hostnames with multiple dots in a + * sequence. Also ensures that the length stays below + * HOST_NAME_MAX. */ + + for (p = s, dot = true; *p; p++) { + if (*p == '.') { + if (dot) + return false; + + dot = true; + n_dots ++; + } else { + if (!hostname_valid_char(*p)) + return false; + + dot = false; + } + } + + if (dot && (n_dots < 2 || !allow_trailing_dot)) + return false; + + if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on + * Linux, but DNS allows domain names + * up to 255 characters */ + return false; + + return true; +} + +char* hostname_cleanup(char *s) { + char *p, *d; + bool dot; + + assert(s); + + for (p = s, d = s, dot = true; *p; p++) { + if (*p == '.') { + if (dot) + continue; + + *(d++) = '.'; + dot = true; + } else if (hostname_valid_char(*p)) { + *(d++) = *p; + dot = false; + } + + } + + if (dot && d > s) + d[-1] = 0; + else + *d = 0; + + strshorten(s, HOST_NAME_MAX); + + return s; +} + +bool is_localhost(const char *hostname) { + assert(hostname); + + /* This tries to identify local host and domain names + * described in RFC6761 plus the redhatism of .localdomain */ + + return strcaseeq(hostname, "localhost") || + strcaseeq(hostname, "localhost.") || + strcaseeq(hostname, "localdomain.") || + strcaseeq(hostname, "localdomain") || + endswith_no_case(hostname, ".localhost") || + endswith_no_case(hostname, ".localhost.") || + endswith_no_case(hostname, ".localdomain") || + endswith_no_case(hostname, ".localdomain."); +} + +#if 0 /* NM_IGNORED */ +bool is_gateway_hostname(const char *hostname) { + assert(hostname); + + /* This tries to identify the valid syntaxes for the our + * synthetic "gateway" host. */ + + return + strcaseeq(hostname, "gateway") || + strcaseeq(hostname, "gateway."); +} + +int sethostname_idempotent(const char *s) { + char buf[HOST_NAME_MAX + 1] = {}; + + assert(s); + + if (gethostname(buf, sizeof(buf)) < 0) + return -errno; + + if (streq(buf, s)) + return 0; + + if (sethostname(s, strlen(s)) < 0) + return -errno; + + return 1; +} + +int read_hostname_config(const char *path, char **hostname) { + _cleanup_fclose_ FILE *f = NULL; + char l[LINE_MAX]; + char *name = NULL; + + assert(path); + assert(hostname); + + f = fopen(path, "re"); + if (!f) + return -errno; + + /* may have comments, ignore them */ + FOREACH_LINE(l, f, return -errno) { + truncate_nl(l); + if (l[0] != '\0' && l[0] != '#') { + /* found line with value */ + name = hostname_cleanup(l); + name = strdup(name); + if (!name) + return -ENOMEM; + break; + } + } + + if (!name) + /* no non-empty line found */ + return -ENOENT; + + *hostname = name; + return 0; +} +#endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/hostname-util.h b/src/systemd/src/basic/hostname-util.h new file mode 100644 index 00000000..a2e69200 --- /dev/null +++ b/src/systemd/src/basic/hostname-util.h @@ -0,0 +1,44 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010-2015 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include + +#include "macro.h" + +bool hostname_is_set(void); + +char* gethostname_malloc(void); + +bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_; +char* hostname_cleanup(char *s); + +#define machine_name_is_valid(s) hostname_is_valid(s, false) + +bool is_localhost(const char *hostname); +bool is_gateway_hostname(const char *hostname); + +int sethostname_idempotent(const char *s); + +int read_hostname_config(const char *path, char **hostname); diff --git a/src/systemd/src/basic/in-addr-util.c b/src/systemd/src/basic/in-addr-util.c new file mode 100644 index 00000000..5027f401 --- /dev/null +++ b/src/systemd/src/basic/in-addr-util.c @@ -0,0 +1,360 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include + +#include "alloc-util.h" +#include "in-addr-util.h" +#include "macro.h" +#include "util.h" + +int in_addr_is_null(int family, const union in_addr_union *u) { + assert(u); + + if (family == AF_INET) + return u->in.s_addr == 0; + + if (family == AF_INET6) + return + u->in6.s6_addr32[0] == 0 && + u->in6.s6_addr32[1] == 0 && + u->in6.s6_addr32[2] == 0 && + u->in6.s6_addr32[3] == 0; + + return -EAFNOSUPPORT; +} + +int in_addr_is_link_local(int family, const union in_addr_union *u) { + assert(u); + + if (family == AF_INET) + return (be32toh(u->in.s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16); + + if (family == AF_INET6) + return IN6_IS_ADDR_LINKLOCAL(&u->in6); + + return -EAFNOSUPPORT; +} + +int in_addr_is_localhost(int family, const union in_addr_union *u) { + assert(u); + + if (family == AF_INET) + /* All of 127.x.x.x is localhost. */ + return (be32toh(u->in.s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24; + + if (family == AF_INET6) + return IN6_IS_ADDR_LOOPBACK(&u->in6); + + return -EAFNOSUPPORT; +} + +int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) { + assert(a); + assert(b); + + if (family == AF_INET) + return a->in.s_addr == b->in.s_addr; + + if (family == AF_INET6) + return + a->in6.s6_addr32[0] == b->in6.s6_addr32[0] && + a->in6.s6_addr32[1] == b->in6.s6_addr32[1] && + a->in6.s6_addr32[2] == b->in6.s6_addr32[2] && + a->in6.s6_addr32[3] == b->in6.s6_addr32[3]; + + return -EAFNOSUPPORT; +} + +int in_addr_prefix_intersect( + int family, + const union in_addr_union *a, + unsigned aprefixlen, + const union in_addr_union *b, + unsigned bprefixlen) { + + unsigned m; + + assert(a); + assert(b); + + /* Checks whether there are any addresses that are in both + * networks */ + + m = MIN(aprefixlen, bprefixlen); + + if (family == AF_INET) { + uint32_t x, nm; + + x = be32toh(a->in.s_addr ^ b->in.s_addr); + nm = (m == 0) ? 0 : 0xFFFFFFFFUL << (32 - m); + + return (x & nm) == 0; + } + + if (family == AF_INET6) { + unsigned i; + + if (m > 128) + m = 128; + + for (i = 0; i < 16; i++) { + uint8_t x, nm; + + x = a->in6.s6_addr[i] ^ b->in6.s6_addr[i]; + + if (m < 8) + nm = 0xFF << (8 - m); + else + nm = 0xFF; + + if ((x & nm) != 0) + return 0; + + if (m > 8) + m -= 8; + else + m = 0; + } + + return 1; + } + + return -EAFNOSUPPORT; +} + +int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) { + assert(u); + + /* Increases the network part of an address by one. Returns + * positive it that succeeds, or 0 if this overflows. */ + + if (prefixlen <= 0) + return 0; + + if (family == AF_INET) { + uint32_t c, n; + + if (prefixlen > 32) + prefixlen = 32; + + c = be32toh(u->in.s_addr); + n = c + (1UL << (32 - prefixlen)); + if (n < c) + return 0; + n &= 0xFFFFFFFFUL << (32 - prefixlen); + + u->in.s_addr = htobe32(n); + return 1; + } + + if (family == AF_INET6) { + struct in6_addr add = {}, result; + uint8_t overflow = 0; + unsigned i; + + if (prefixlen > 128) + prefixlen = 128; + + /* First calculate what we have to add */ + add.s6_addr[(prefixlen-1) / 8] = 1 << (7 - (prefixlen-1) % 8); + + for (i = 16; i > 0; i--) { + unsigned j = i - 1; + + result.s6_addr[j] = u->in6.s6_addr[j] + add.s6_addr[j] + overflow; + overflow = (result.s6_addr[j] < u->in6.s6_addr[j]); + } + + if (overflow) + return 0; + + u->in6 = result; + return 1; + } + + return -EAFNOSUPPORT; +} + +int in_addr_to_string(int family, const union in_addr_union *u, char **ret) { + char *x; + size_t l; + + assert(u); + assert(ret); + + if (family == AF_INET) + l = INET_ADDRSTRLEN; + else if (family == AF_INET6) + l = INET6_ADDRSTRLEN; + else + return -EAFNOSUPPORT; + + x = new(char, l); + if (!x) + return -ENOMEM; + + errno = 0; + if (!inet_ntop(family, u, x, l)) { + free(x); + return errno ? -errno : -EINVAL; + } + + *ret = x; + return 0; +} + +int in_addr_from_string(int family, const char *s, union in_addr_union *ret) { + + assert(s); + assert(ret); + + if (!IN_SET(family, AF_INET, AF_INET6)) + return -EAFNOSUPPORT; + + errno = 0; + if (inet_pton(family, s, ret) <= 0) + return errno ? -errno : -EINVAL; + + return 0; +} + +int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret) { + int r; + + assert(s); + assert(family); + assert(ret); + + r = in_addr_from_string(AF_INET, s, ret); + if (r >= 0) { + *family = AF_INET; + return 0; + } + + r = in_addr_from_string(AF_INET6, s, ret); + if (r >= 0) { + *family = AF_INET6; + return 0; + } + + return -EINVAL; +} + +unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr) { + assert(addr); + + return 32 - u32ctz(be32toh(addr->s_addr)); +} + +struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen) { + assert(addr); + assert(prefixlen <= 32); + + /* Shifting beyond 32 is not defined, handle this specially. */ + if (prefixlen == 0) + addr->s_addr = 0; + else + addr->s_addr = htobe32((0xffffffff << (32 - prefixlen)) & 0xffffffff); + + return addr; +} + +int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen) { + uint8_t msb_octet = *(uint8_t*) addr; + + /* addr may not be aligned, so make sure we only access it byte-wise */ + + assert(addr); + assert(prefixlen); + + if (msb_octet < 128) + /* class A, leading bits: 0 */ + *prefixlen = 8; + else if (msb_octet < 192) + /* class B, leading bits 10 */ + *prefixlen = 16; + else if (msb_octet < 224) + /* class C, leading bits 110 */ + *prefixlen = 24; + else + /* class D or E, no default prefixlen */ + return -ERANGE; + + return 0; +} + +int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask) { + unsigned char prefixlen; + int r; + + assert(addr); + assert(mask); + + r = in_addr_default_prefixlen(addr, &prefixlen); + if (r < 0) + return r; + + in_addr_prefixlen_to_netmask(mask, prefixlen); + return 0; +} + +int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen) { + assert(addr); + + if (family == AF_INET) { + struct in_addr mask; + + if (!in_addr_prefixlen_to_netmask(&mask, prefixlen)) + return -EINVAL; + + addr->in.s_addr &= mask.s_addr; + return 0; + } + + if (family == AF_INET6) { + unsigned i; + + for (i = 0; i < 16; i++) { + uint8_t mask; + + if (prefixlen >= 8) { + mask = 0xFF; + prefixlen -= 8; + } else { + mask = 0xFF << (8 - prefixlen); + prefixlen = 0; + } + + addr->in6.s6_addr[i] &= mask; + } + + return 0; + } + + return -EAFNOSUPPORT; +} diff --git a/src/systemd/src/basic/in-addr-util.h b/src/systemd/src/basic/in-addr-util.h new file mode 100644 index 00000000..f94aba83 --- /dev/null +++ b/src/systemd/src/basic/in-addr-util.h @@ -0,0 +1,58 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include + +#include "macro.h" +#include "util.h" + +union in_addr_union { + struct in_addr in; + struct in6_addr in6; +}; + +int in_addr_is_null(int family, const union in_addr_union *u); +int in_addr_is_link_local(int family, const union in_addr_union *u); +int in_addr_is_localhost(int family, const union in_addr_union *u); +int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b); +int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen); +int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen); +int in_addr_to_string(int family, const union in_addr_union *u, char **ret); +int in_addr_from_string(int family, const char *s, union in_addr_union *ret); +int in_addr_from_string_auto(const char *s, int *family, union in_addr_union *ret); +unsigned char in_addr_netmask_to_prefixlen(const struct in_addr *addr); +struct in_addr* in_addr_prefixlen_to_netmask(struct in_addr *addr, unsigned char prefixlen); +int in_addr_default_prefixlen(const struct in_addr *addr, unsigned char *prefixlen); +int in_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mask); +int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen); + +static inline size_t FAMILY_ADDRESS_SIZE(int family) { + assert(family == AF_INET || family == AF_INET6); + return family == AF_INET6 ? 16 : 4; +} + +#define IN_ADDR_NULL ((union in_addr_union) {}) diff --git a/src/systemd/src/basic/io-util.c b/src/systemd/src/basic/io-util.c new file mode 100644 index 00000000..c7bb1e78 --- /dev/null +++ b/src/systemd/src/basic/io-util.c @@ -0,0 +1,268 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include + +#include "io-util.h" +#include "time-util.h" + +int flush_fd(int fd) { + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN, + }; + + for (;;) { + char buf[LINE_MAX]; + ssize_t l; + int r; + + r = poll(&pollfd, 1, 0); + if (r < 0) { + if (errno == EINTR) + continue; + + return -errno; + + } else if (r == 0) + return 0; + + l = read(fd, buf, sizeof(buf)); + if (l < 0) { + + if (errno == EINTR) + continue; + + if (errno == EAGAIN) + return 0; + + return -errno; + } else if (l == 0) + return 0; + } +} + +ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) { + uint8_t *p = buf; + ssize_t n = 0; + + assert(fd >= 0); + assert(buf); + + /* If called with nbytes == 0, let's call read() at least + * once, to validate the operation */ + + if (nbytes > (size_t) SSIZE_MAX) + return -EINVAL; + + do { + ssize_t k; + + k = read(fd, p, nbytes); + if (k < 0) { + if (errno == EINTR) + continue; + + if (errno == EAGAIN && do_poll) { + + /* We knowingly ignore any return value here, + * and expect that any error/EOF is reported + * via read() */ + + (void) fd_wait_for_event(fd, POLLIN, USEC_INFINITY); + continue; + } + + return n > 0 ? n : -errno; + } + + if (k == 0) + return n; + + assert((size_t) k <= nbytes); + + p += k; + nbytes -= k; + n += k; + } while (nbytes > 0); + + return n; +} + +int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) { + ssize_t n; + + n = loop_read(fd, buf, nbytes, do_poll); + if (n < 0) + return (int) n; + if ((size_t) n != nbytes) + return -EIO; + + return 0; +} + +int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) { + const uint8_t *p = buf; + + assert(fd >= 0); + assert(buf); + + if (nbytes > (size_t) SSIZE_MAX) + return -EINVAL; + + do { + ssize_t k; + + k = write(fd, p, nbytes); + if (k < 0) { + if (errno == EINTR) + continue; + + if (errno == EAGAIN && do_poll) { + /* We knowingly ignore any return value here, + * and expect that any error/EOF is reported + * via write() */ + + (void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY); + continue; + } + + return -errno; + } + + if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */ + return -EIO; + + assert((size_t) k <= nbytes); + + p += k; + nbytes -= k; + } while (nbytes > 0); + + return 0; +} + +int pipe_eof(int fd) { + struct pollfd pollfd = { + .fd = fd, + .events = POLLIN|POLLHUP, + }; + + int r; + + r = poll(&pollfd, 1, 0); + if (r < 0) + return -errno; + + if (r == 0) + return 0; + + return pollfd.revents & POLLHUP; +} + +int fd_wait_for_event(int fd, int event, usec_t t) { + + struct pollfd pollfd = { + .fd = fd, + .events = event, + }; + + struct timespec ts; + int r; + + r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); + if (r < 0) + return -errno; + + if (r == 0) + return 0; + + return pollfd.revents; +} + +static size_t nul_length(const uint8_t *p, size_t sz) { + size_t n = 0; + + while (sz > 0) { + if (*p != 0) + break; + + n++; + p++; + sz--; + } + + return n; +} + +ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) { + const uint8_t *q, *w, *e; + ssize_t l; + + q = w = p; + e = q + sz; + while (q < e) { + size_t n; + + n = nul_length(q, e - q); + + /* If there are more than the specified run length of + * NUL bytes, or if this is the beginning or the end + * of the buffer, then seek instead of write */ + if ((n > run_length) || + (n > 0 && q == p) || + (n > 0 && q + n >= e)) { + if (q > w) { + l = write(fd, w, q - w); + if (l < 0) + return -errno; + if (l != q -w) + return -EIO; + } + + if (lseek(fd, n, SEEK_CUR) == (off_t) -1) + return -errno; + + q += n; + w = q; + } else if (n > 0) + q += n; + else + q ++; + } + + if (q > w) { + l = write(fd, w, q - w); + if (l < 0) + return -errno; + if (l != q - w) + return -EIO; + } + + return q - (const uint8_t*) p; +} diff --git a/src/systemd/src/basic/io-util.h b/src/systemd/src/basic/io-util.h new file mode 100644 index 00000000..a6260965 --- /dev/null +++ b/src/systemd/src/basic/io-util.h @@ -0,0 +1,81 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include + +#include "macro.h" +#include "time-util.h" + +int flush_fd(int fd); + +ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll); +int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll); +int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll); + +int pipe_eof(int fd); + +int fd_wait_for_event(int fd, int event, usec_t timeout); + +ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length); + +#define IOVEC_SET_STRING(i, s) \ + do { \ + struct iovec *_i = &(i); \ + char *_s = (char *)(s); \ + _i->iov_base = _s; \ + _i->iov_len = strlen(_s); \ + } while(false) + +static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, unsigned n) { + unsigned j; + size_t r = 0; + + for (j = 0; j < n; j++) + r += i[j].iov_len; + + return r; +} + +static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { + unsigned j; + + for (j = 0; j < n; j++) { + size_t sub; + + if (_unlikely_(k <= 0)) + break; + + sub = MIN(i[j].iov_len, k); + i[j].iov_len -= sub; + i[j].iov_base = (uint8_t*) i[j].iov_base + sub; + k -= sub; + } + + return k; +} diff --git a/src/systemd/src/basic/list.h b/src/systemd/src/basic/list.h new file mode 100644 index 00000000..3ac38418 --- /dev/null +++ b/src/systemd/src/basic/list.h @@ -0,0 +1,186 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +/* The head of the linked list. Use this in the structure that shall + * contain the head of the linked list */ +#define LIST_HEAD(t,name) \ + t *name + +/* The pointers in the linked list's items. Use this in the item structure */ +#define LIST_FIELDS(t,name) \ + t *name##_next, *name##_prev + +/* Initialize the list's head */ +#define LIST_HEAD_INIT(head) \ + do { \ + (head) = NULL; } \ + while(false) + +/* Initialize a list item */ +#define LIST_INIT(name,item) \ + do { \ + typeof(*(item)) *_item = (item); \ + assert(_item); \ + _item->name##_prev = _item->name##_next = NULL; \ + } while(false) + +/* Prepend an item to the list */ +#define LIST_PREPEND(name,head,item) \ + do { \ + typeof(*(head)) **_head = &(head), *_item = (item); \ + assert(_item); \ + if ((_item->name##_next = *_head)) \ + _item->name##_next->name##_prev = _item; \ + _item->name##_prev = NULL; \ + *_head = _item; \ + } while(false) + +/* Append an item to the list */ +#define LIST_APPEND(name,head,item) \ + do { \ + typeof(*(head)) *_tail; \ + LIST_FIND_TAIL(name,head,_tail); \ + LIST_INSERT_AFTER(name,head,_tail,item); \ + } while(false) + +/* Remove an item from the list */ +#define LIST_REMOVE(name,head,item) \ + do { \ + typeof(*(head)) **_head = &(head), *_item = (item); \ + assert(_item); \ + if (_item->name##_next) \ + _item->name##_next->name##_prev = _item->name##_prev; \ + if (_item->name##_prev) \ + _item->name##_prev->name##_next = _item->name##_next; \ + else { \ + assert(*_head == _item); \ + *_head = _item->name##_next; \ + } \ + _item->name##_next = _item->name##_prev = NULL; \ + } while(false) + +/* Find the head of the list */ +#define LIST_FIND_HEAD(name,item,head) \ + do { \ + typeof(*(item)) *_item = (item); \ + if (!_item) \ + (head) = NULL; \ + else { \ + while (_item->name##_prev) \ + _item = _item->name##_prev; \ + (head) = _item; \ + } \ + } while (false) + +/* Find the tail of the list */ +#define LIST_FIND_TAIL(name,item,tail) \ + do { \ + typeof(*(item)) *_item = (item); \ + if (!_item) \ + (tail) = NULL; \ + else { \ + while (_item->name##_next) \ + _item = _item->name##_next; \ + (tail) = _item; \ + } \ + } while (false) + +/* Insert an item after another one (a = where, b = what) */ +#define LIST_INSERT_AFTER(name,head,a,b) \ + do { \ + typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \ + assert(_b); \ + if (!_a) { \ + if ((_b->name##_next = *_head)) \ + _b->name##_next->name##_prev = _b; \ + _b->name##_prev = NULL; \ + *_head = _b; \ + } else { \ + if ((_b->name##_next = _a->name##_next)) \ + _b->name##_next->name##_prev = _b; \ + _b->name##_prev = _a; \ + _a->name##_next = _b; \ + } \ + } while(false) + +/* Insert an item before another one (a = where, b = what) */ +#define LIST_INSERT_BEFORE(name,head,a,b) \ + do { \ + typeof(*(head)) **_head = &(head), *_a = (a), *_b = (b); \ + assert(_b); \ + if (!_a) { \ + if (!*_head) { \ + _b->name##_next = NULL; \ + _b->name##_prev = NULL; \ + *_head = _b; \ + } else { \ + typeof(*(head)) *_tail = (head); \ + while (_tail->name##_next) \ + _tail = _tail->name##_next; \ + _b->name##_next = NULL; \ + _b->name##_prev = _tail; \ + _tail->name##_next = _b; \ + } \ + } else { \ + if ((_b->name##_prev = _a->name##_prev)) \ + _b->name##_prev->name##_next = _b; \ + _b->name##_next = _a; \ + _a->name##_prev = _b; \ + } \ + } while(false) + +#define LIST_JUST_US(name,item) \ + (!(item)->name##_prev && !(item)->name##_next) \ + +#define LIST_FOREACH(name,i,head) \ + for ((i) = (head); (i); (i) = (i)->name##_next) + +#define LIST_FOREACH_SAFE(name,i,n,head) \ + for ((i) = (head); (i) && (((n) = (i)->name##_next), 1); (i) = (n)) + +#define LIST_FOREACH_BEFORE(name,i,p) \ + for ((i) = (p)->name##_prev; (i); (i) = (i)->name##_prev) + +#define LIST_FOREACH_AFTER(name,i,p) \ + for ((i) = (p)->name##_next; (i); (i) = (i)->name##_next) + +/* Iterate through all the members of the list p is included in, but skip over p */ +#define LIST_FOREACH_OTHERS(name,i,p) \ + for (({ \ + (i) = (p); \ + while ((i) && (i)->name##_prev) \ + (i) = (i)->name##_prev; \ + if ((i) == (p)) \ + (i) = (p)->name##_next; \ + }); \ + (i); \ + (i) = (i)->name##_next == (p) ? (p)->name##_next : (i)->name##_next) + +/* Loop starting from p->next until p->prev. + p can be adjusted meanwhile. */ +#define LIST_LOOP_BUT_ONE(name,i,head,p) \ + for ((i) = (p)->name##_next ? (p)->name##_next : (head); \ + (i) != (p); \ + (i) = (i)->name##_next ? (i)->name##_next : (head)) diff --git a/src/systemd/src/basic/log.h b/src/systemd/src/basic/log.h new file mode 100644 index 00000000..bc316189 --- /dev/null +++ b/src/systemd/src/basic/log.h @@ -0,0 +1,246 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include + +#include "sd-id128.h" + +#include "macro.h" + +typedef enum LogTarget{ + LOG_TARGET_CONSOLE, + LOG_TARGET_CONSOLE_PREFIXED, + LOG_TARGET_KMSG, + LOG_TARGET_JOURNAL, + LOG_TARGET_JOURNAL_OR_KMSG, + LOG_TARGET_SYSLOG, + LOG_TARGET_SYSLOG_OR_KMSG, + LOG_TARGET_AUTO, /* console if stderr is tty, JOURNAL_OR_KMSG otherwise */ + LOG_TARGET_SAFE, /* console if stderr is tty, KMSG otherwise */ + LOG_TARGET_NULL, + _LOG_TARGET_MAX, + _LOG_TARGET_INVALID = -1 +} LogTarget; + +void log_set_target(LogTarget target); +void log_set_max_level(int level); +void log_set_facility(int facility); + +int log_set_target_from_string(const char *e); +int log_set_max_level_from_string(const char *e); + +void log_show_color(bool b); +bool log_get_show_color(void) _pure_; +void log_show_location(bool b); +bool log_get_show_location(void) _pure_; + +int log_show_color_from_string(const char *e); +int log_show_location_from_string(const char *e); + +LogTarget log_get_target(void) _pure_; +int log_get_max_level(void) _pure_; + +int log_open(void); +void log_close(void); +void log_forget_fds(void); + +void log_close_syslog(void); +void log_close_journal(void); +void log_close_kmsg(void); +void log_close_console(void); + +void log_parse_environment(void); + +#if 0 /* NM_IGNORED */ +int log_internal( + int level, + int error, + const char *file, + int line, + const char *func, + const char *format, ...) _printf_(6,7); + +int log_internalv( + int level, + int error, + const char *file, + int line, + const char *func, + const char *format, + va_list ap) _printf_(6,0); + +int log_object_internal( + int level, + int error, + const char *file, + int line, + const char *func, + const char *object_field, + const char *object, + const char *format, ...) _printf_(8,9); + +int log_object_internalv( + int level, + int error, + const char*file, + int line, + const char *func, + const char *object_field, + const char *object, + const char *format, + va_list ap) _printf_(8,0); + +int log_struct_internal( + int level, + int error, + const char *file, + int line, + const char *func, + const char *format, ...) _printf_(6,0) _sentinel_; + +int log_oom_internal( + const char *file, + int line, + const char *func); + +/* This modifies the buffer passed! */ +int log_dump_internal( + int level, + int error, + const char *file, + int line, + const char *func, + char *buffer); + +/* Logging for various assertions */ +noreturn void log_assert_failed( + const char *text, + const char *file, + int line, + const char *func); + +noreturn void log_assert_failed_unreachable( + const char *text, + const char *file, + int line, + const char *func); + +void log_assert_failed_return( + const char *text, + const char *file, + int line, + const char *func); + +/* Logging with level */ +#define log_full_errno(level, error, ...) \ + ({ \ + int _level = (level), _e = (error); \ + (log_get_max_level() >= LOG_PRI(_level)) \ + ? log_internal(_level, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \ + : -abs(_e); \ + }) +#endif /* NM_IGNORED */ + +#define log_full(level, ...) log_full_errno(level, 0, __VA_ARGS__) + +/* Normal logging */ +#define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__) +#define log_info(...) log_full(LOG_INFO, __VA_ARGS__) +#define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__) +#define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__) +#define log_error(...) log_full(LOG_ERR, __VA_ARGS__) +#define log_emergency(...) log_full(getpid() == 1 ? LOG_EMERG : LOG_ERR, __VA_ARGS__) + +/* Logging triggered by an errno-like error */ +#define log_debug_errno(error, ...) log_full_errno(LOG_DEBUG, error, __VA_ARGS__) +#define log_info_errno(error, ...) log_full_errno(LOG_INFO, error, __VA_ARGS__) +#define log_notice_errno(error, ...) log_full_errno(LOG_NOTICE, error, __VA_ARGS__) +#define log_warning_errno(error, ...) log_full_errno(LOG_WARNING, error, __VA_ARGS__) +#define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__) +#define log_emergency_errno(error, ...) log_full_errno(getpid() == 1 ? LOG_EMERG : LOG_ERR, error, __VA_ARGS__) + +#ifdef LOG_TRACE +# define log_trace(...) log_debug(__VA_ARGS__) +#else +# define log_trace(...) do {} while(0) +#endif + +/* Structured logging */ +#define log_struct(level, ...) log_struct_internal(level, 0, __FILE__, __LINE__, __func__, __VA_ARGS__) +#define log_struct_errno(level, error, ...) log_struct_internal(level, error, __FILE__, __LINE__, __func__, __VA_ARGS__) + +/* This modifies the buffer passed! */ +#define log_dump(level, buffer) log_dump_internal(level, 0, __FILE__, __LINE__, __func__, buffer) + +#define log_oom() log_oom_internal(__FILE__, __LINE__, __func__) + +bool log_on_console(void) _pure_; + +const char *log_target_to_string(LogTarget target) _const_; +LogTarget log_target_from_string(const char *s) _pure_; + +/* Helpers to prepare various fields for structured logging */ +#define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__ +#define LOG_MESSAGE_ID(x) "MESSAGE_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(x) + +void log_received_signal(int level, const struct signalfd_siginfo *si); + +void log_set_upgrade_syslog_to_journal(bool b); + +int log_syntax_internal( + const char *unit, + int level, + const char *config_file, + unsigned config_line, + int error, + const char *file, + int line, + const char *func, + const char *format, ...) _printf_(9, 10); + +#define log_syntax(unit, level, config_file, config_line, error, ...) \ + ({ \ + int _level = (level), _e = (error); \ + (log_get_max_level() >= LOG_PRI(_level)) \ + ? log_syntax_internal(unit, _level, config_file, config_line, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \ + : -abs(_e); \ + }) + +#define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \ + ({ \ + int _level = (level); \ + if (log_get_max_level() >= LOG_PRI(_level)) { \ + _cleanup_free_ char *_p = NULL; \ + _p = utf8_escape_invalid(rvalue); \ + log_syntax_internal(unit, _level, config_file, config_line, 0, __FILE__, __LINE__, __func__, \ + "String is not UTF-8 clean, ignoring assignment: %s", strna(_p)); \ + } \ + -EINVAL; \ + }) diff --git a/src/systemd/src/basic/macro.h b/src/systemd/src/basic/macro.h new file mode 100644 index 00000000..222f3c42 --- /dev/null +++ b/src/systemd/src/basic/macro.h @@ -0,0 +1,379 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include + +#define _printf_(a,b) __attribute__ ((format (printf, a, b))) +#define _alloc_(...) __attribute__ ((alloc_size(__VA_ARGS__))) +#define _sentinel_ __attribute__ ((sentinel)) +#define _unused_ __attribute__ ((unused)) +#define _destructor_ __attribute__ ((destructor)) +#define _pure_ __attribute__ ((pure)) +#define _const_ __attribute__ ((const)) +#define _deprecated_ __attribute__ ((deprecated)) +#define _packed_ __attribute__ ((packed)) +#define _malloc_ __attribute__ ((malloc)) +#define _weak_ __attribute__ ((weak)) +#define _likely_(x) (__builtin_expect(!!(x),1)) +#define _unlikely_(x) (__builtin_expect(!!(x),0)) +#define _public_ __attribute__ ((visibility("default"))) +#define _hidden_ __attribute__ ((visibility("hidden"))) +#define _weakref_(x) __attribute__((weakref(#x))) +#define _alignas_(x) __attribute__((aligned(__alignof(x)))) +#define _cleanup_(x) __attribute__((cleanup(x))) + +#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) || defined (__clang__) +/* Temporarily disable some warnings */ +#define DISABLE_WARNING_DECLARATION_AFTER_STATEMENT \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wdeclaration-after-statement\"") + +#define DISABLE_WARNING_FORMAT_NONLITERAL \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wformat-nonliteral\"") + +#define DISABLE_WARNING_MISSING_PROTOTYPES \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wmissing-prototypes\"") + +#define DISABLE_WARNING_NONNULL \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wnonnull\"") + +#define DISABLE_WARNING_SHADOW \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wshadow\"") + +#define DISABLE_WARNING_INCOMPATIBLE_POINTER_TYPES \ + _Pragma("GCC diagnostic push"); \ + _Pragma("GCC diagnostic ignored \"-Wincompatible-pointer-types\"") + +#define REENABLE_WARNING \ + _Pragma("GCC diagnostic pop") +#else +#define DISABLE_WARNING_DECLARATION_AFTER_STATEMENT +#define DISABLE_WARNING_FORMAT_NONLITERAL +#define DISABLE_WARNING_MISSING_PROTOTYPES +#define DISABLE_WARNING_NONNULL +#define DISABLE_WARNING_SHADOW +#define REENABLE_WARNING +#endif + +/* automake test harness */ +#define EXIT_TEST_SKIP 77 + +#define XSTRINGIFY(x) #x +#define STRINGIFY(x) XSTRINGIFY(x) + +#define XCONCATENATE(x, y) x ## y +#define CONCATENATE(x, y) XCONCATENATE(x, y) + +#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq)) +#define UNIQ __COUNTER__ + +/* Rounds up */ + +#define ALIGN4(l) (((l) + 3) & ~3) +#define ALIGN8(l) (((l) + 7) & ~7) + +#if __SIZEOF_POINTER__ == 8 +#define ALIGN(l) ALIGN8(l) +#elif __SIZEOF_POINTER__ == 4 +#define ALIGN(l) ALIGN4(l) +#else +#error "Wut? Pointers are neither 4 nor 8 bytes long?" +#endif + +#define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) (p))) +#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) (p))) +#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) (p))) + +static inline size_t ALIGN_TO(size_t l, size_t ali) { + return ((l + ali - 1) & ~(ali - 1)); +} + +#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) (p), (ali))) + +/* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */ +static inline unsigned long ALIGN_POWER2(unsigned long u) { + /* clz(0) is undefined */ + if (u == 1) + return 1; + + /* left-shift overflow is undefined */ + if (__builtin_clzl(u - 1UL) < 1) + return 0; + + return 1UL << (sizeof(u) * 8 - __builtin_clzl(u - 1UL)); +} + +#define ELEMENTSOF(x) \ + __extension__ (__builtin_choose_expr( \ + !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \ + sizeof(x)/sizeof((x)[0]), \ + (void)0)) +/* + * container_of - cast a member of a structure out to the containing structure + * @ptr: the pointer to the member. + * @type: the type of the container struct this is embedded in. + * @member: the name of the member within the struct. + */ +#define container_of(ptr, type, member) __container_of(UNIQ, (ptr), type, member) +#define __container_of(uniq, ptr, type, member) \ + __extension__ ({ \ + const typeof( ((type*)0)->member ) *UNIQ_T(A, uniq) = (ptr); \ + (type*)( (char *)UNIQ_T(A, uniq) - offsetof(type,member) ); \ + }) + +#undef MAX +#define MAX(a, b) __MAX(UNIQ, (a), UNIQ, (b)) +#define __MAX(aq, a, bq, b) \ + __extension__ ({ \ + const typeof(a) UNIQ_T(A, aq) = (a); \ + const typeof(b) UNIQ_T(B, bq) = (b); \ + UNIQ_T(A,aq) > UNIQ_T(B,bq) ? UNIQ_T(A,aq) : UNIQ_T(B,bq); \ + }) + +/* evaluates to (void) if _A or _B are not constant or of different types */ +#define CONST_MAX(_A, _B) \ + __extension__ (__builtin_choose_expr( \ + __builtin_constant_p(_A) && \ + __builtin_constant_p(_B) && \ + __builtin_types_compatible_p(typeof(_A), typeof(_B)), \ + ((_A) > (_B)) ? (_A) : (_B), \ + (void)0)) + +/* takes two types and returns the size of the larger one */ +#define MAXSIZE(A, B) (sizeof(union _packed_ { typeof(A) a; typeof(B) b; })) + +#define MAX3(x,y,z) \ + __extension__ ({ \ + const typeof(x) _c = MAX(x,y); \ + MAX(_c, z); \ + }) + +#undef MIN +#define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b)) +#define __MIN(aq, a, bq, b) \ + __extension__ ({ \ + const typeof(a) UNIQ_T(A, aq) = (a); \ + const typeof(b) UNIQ_T(B, bq) = (b); \ + UNIQ_T(A,aq) < UNIQ_T(B,bq) ? UNIQ_T(A,aq) : UNIQ_T(B,bq); \ + }) + +#define MIN3(x,y,z) \ + __extension__ ({ \ + const typeof(x) _c = MIN(x,y); \ + MIN(_c, z); \ + }) + +#define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b)) +#define __LESS_BY(aq, a, bq, b) \ + __extension__ ({ \ + const typeof(a) UNIQ_T(A, aq) = (a); \ + const typeof(b) UNIQ_T(B, bq) = (b); \ + UNIQ_T(A,aq) > UNIQ_T(B,bq) ? UNIQ_T(A,aq) - UNIQ_T(B,bq) : 0; \ + }) + +#undef CLAMP +#define CLAMP(x, low, high) __CLAMP(UNIQ, (x), UNIQ, (low), UNIQ, (high)) +#define __CLAMP(xq, x, lowq, low, highq, high) \ + __extension__ ({ \ + const typeof(x) UNIQ_T(X,xq) = (x); \ + const typeof(low) UNIQ_T(LOW,lowq) = (low); \ + const typeof(high) UNIQ_T(HIGH,highq) = (high); \ + UNIQ_T(X,xq) > UNIQ_T(HIGH,highq) ? \ + UNIQ_T(HIGH,highq) : \ + UNIQ_T(X,xq) < UNIQ_T(LOW,lowq) ? \ + UNIQ_T(LOW,lowq) : \ + UNIQ_T(X,xq); \ + }) + +/* [(x + y - 1) / y] suffers from an integer overflow, even though the + * computation should be possible in the given type. Therefore, we use + * [x / y + !!(x % y)]. Note that on "Real CPUs" a division returns both the + * quotient and the remainder, so both should be equally fast. */ +#define DIV_ROUND_UP(_x, _y) \ + __extension__ ({ \ + const typeof(_x) __x = (_x); \ + const typeof(_y) __y = (_y); \ + (__x / __y + !!(__x % __y)); \ + }) + +#define assert_message_se(expr, message) \ + do { \ + if (_unlikely_(!(expr))) \ + log_assert_failed(message, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + } while (false) + +#define assert_se(expr) assert_message_se(expr, #expr) + +/* We override the glibc assert() here. */ +#undef assert +#ifdef NDEBUG +#define assert(expr) do {} while(false) +#else +#define assert(expr) assert_message_se(expr, #expr) +#endif + +#define assert_not_reached(t) \ + do { \ + log_assert_failed_unreachable(t, __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + } while (false) + +#if defined(static_assert) +/* static_assert() is sometimes defined in a way that trips up + * -Wdeclaration-after-statement, hence let's temporarily turn off + * this warning around it. */ +#define assert_cc(expr) \ + DISABLE_WARNING_DECLARATION_AFTER_STATEMENT; \ + static_assert(expr, #expr); \ + REENABLE_WARNING +#else +#define assert_cc(expr) \ + DISABLE_WARNING_DECLARATION_AFTER_STATEMENT; \ + struct CONCATENATE(_assert_struct_, __COUNTER__) { \ + char x[(expr) ? 0 : -1]; \ + }; \ + REENABLE_WARNING +#endif + +#define assert_log(expr, message) ((_likely_(expr)) \ + ? (true) \ + : (log_assert_failed_return(message, __FILE__, __LINE__, __PRETTY_FUNCTION__), false)) + +#define assert_return(expr, r) \ + do { \ + if (!assert_log(expr, #expr)) \ + return (r); \ + } while (false) + +#define assert_return_errno(expr, r, err) \ + do { \ + if (!assert_log(expr, #expr)) { \ + errno = err; \ + return (r); \ + } \ + } while (false) + +#define PTR_TO_INT(p) ((int) ((intptr_t) (p))) +#define INT_TO_PTR(u) ((void *) ((intptr_t) (u))) +#define PTR_TO_UINT(p) ((unsigned int) ((uintptr_t) (p))) +#define UINT_TO_PTR(u) ((void *) ((uintptr_t) (u))) + +#define PTR_TO_LONG(p) ((long) ((intptr_t) (p))) +#define LONG_TO_PTR(u) ((void *) ((intptr_t) (u))) +#define PTR_TO_ULONG(p) ((unsigned long) ((uintptr_t) (p))) +#define ULONG_TO_PTR(u) ((void *) ((uintptr_t) (u))) + +#define PTR_TO_INT32(p) ((int32_t) ((intptr_t) (p))) +#define INT32_TO_PTR(u) ((void *) ((intptr_t) (u))) +#define PTR_TO_UINT32(p) ((uint32_t) ((uintptr_t) (p))) +#define UINT32_TO_PTR(u) ((void *) ((uintptr_t) (u))) + +#define PTR_TO_INT64(p) ((int64_t) ((intptr_t) (p))) +#define INT64_TO_PTR(u) ((void *) ((intptr_t) (u))) +#define PTR_TO_UINT64(p) ((uint64_t) ((uintptr_t) (p))) +#define UINT64_TO_PTR(u) ((void *) ((uintptr_t) (u))) + +#define PTR_TO_SIZE(p) ((size_t) ((uintptr_t) (p))) +#define SIZE_TO_PTR(u) ((void *) ((uintptr_t) (u))) + +#define CHAR_TO_STR(x) ((char[2]) { x, 0 }) + +#define char_array_0(x) x[sizeof(x)-1] = 0; + +/* Returns the number of chars needed to format variables of the + * specified type as a decimal string. Adds in extra space for a + * negative '-' prefix (hence works correctly on signed + * types). Includes space for the trailing NUL. */ +#define DECIMAL_STR_MAX(type) \ + (2+(sizeof(type) <= 1 ? 3 : \ + sizeof(type) <= 2 ? 5 : \ + sizeof(type) <= 4 ? 10 : \ + sizeof(type) <= 8 ? 20 : sizeof(int[-2*(sizeof(type) > 8)]))) + +#define DECIMAL_STR_WIDTH(x) \ + ({ \ + typeof(x) _x_ = (x); \ + unsigned ans = 1; \ + while (_x_ /= 10) \ + ans++; \ + ans; \ + }) + +#define SET_FLAG(v, flag, b) \ + (v) = (b) ? ((v) | (flag)) : ((v) & ~(flag)) + +#define IN_SET(x, y, ...) \ + ({ \ + static const typeof(y) _array[] = { (y), __VA_ARGS__ }; \ + const typeof(y) _x = (x); \ + unsigned _i; \ + bool _found = false; \ + for (_i = 0; _i < ELEMENTSOF(_array); _i++) \ + if (_array[_i] == _x) { \ + _found = true; \ + break; \ + } \ + _found; \ + }) + +/* Define C11 thread_local attribute even on older gcc compiler + * version */ +#ifndef thread_local +/* + * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__ + * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 + */ +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16)) +#define thread_local _Thread_local +#else +#define thread_local __thread +#endif +#endif + +/* Define C11 noreturn without and even on older gcc + * compiler versions */ +#ifndef noreturn +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +#define noreturn _Noreturn +#else +#define noreturn __attribute__((noreturn)) +#endif +#endif + +#define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ + static inline void func##p(type *p) { \ + if (*p) \ + func(*p); \ + } \ + struct __useless_struct_to_allow_trailing_semicolon__ + +#include "log.h" diff --git a/src/systemd/src/basic/mempool.c b/src/systemd/src/basic/mempool.c new file mode 100644 index 00000000..511b962f --- /dev/null +++ b/src/systemd/src/basic/mempool.c @@ -0,0 +1,108 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010-2014 Lennart Poettering + Copyright 2014 Michal Schmidt + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +#include "macro.h" +#include "mempool.h" +#include "util.h" + +struct pool { + struct pool *next; + unsigned n_tiles; + unsigned n_used; +}; + +void* mempool_alloc_tile(struct mempool *mp) { + unsigned i; + + /* When a tile is released we add it to the list and simply + * place the next pointer at its offset 0. */ + + assert(mp->tile_size >= sizeof(void*)); + assert(mp->at_least > 0); + + if (mp->freelist) { + void *r; + + r = mp->freelist; + mp->freelist = * (void**) mp->freelist; + return r; + } + + if (_unlikely_(!mp->first_pool) || + _unlikely_(mp->first_pool->n_used >= mp->first_pool->n_tiles)) { + unsigned n; + size_t size; + struct pool *p; + + n = mp->first_pool ? mp->first_pool->n_tiles : 0; + n = MAX(mp->at_least, n * 2); + size = PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n*mp->tile_size); + n = (size - ALIGN(sizeof(struct pool))) / mp->tile_size; + + p = malloc(size); + if (!p) + return NULL; + + p->next = mp->first_pool; + p->n_tiles = n; + p->n_used = 0; + + mp->first_pool = p; + } + + i = mp->first_pool->n_used++; + + return ((uint8_t*) mp->first_pool) + ALIGN(sizeof(struct pool)) + i*mp->tile_size; +} + +void* mempool_alloc0_tile(struct mempool *mp) { + void *p; + + p = mempool_alloc_tile(mp); + if (p) + memzero(p, mp->tile_size); + return p; +} + +void mempool_free_tile(struct mempool *mp, void *p) { + * (void**) p = mp->freelist; + mp->freelist = p; +} + +#ifdef VALGRIND + +void mempool_drop(struct mempool *mp) { + struct pool *p = mp->first_pool; + while (p) { + struct pool *n; + n = p->next; + free(p); + p = n; + } +} + +#endif diff --git a/src/systemd/src/basic/mempool.h b/src/systemd/src/basic/mempool.h new file mode 100644 index 00000000..e9753adb --- /dev/null +++ b/src/systemd/src/basic/mempool.h @@ -0,0 +1,51 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2011-2014 Lennart Poettering + Copyright 2014 Michal Schmidt + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include + +struct pool; + +struct mempool { + struct pool *first_pool; + void *freelist; + size_t tile_size; + unsigned at_least; +}; + +void* mempool_alloc_tile(struct mempool *mp); +void* mempool_alloc0_tile(struct mempool *mp); +void mempool_free_tile(struct mempool *mp, void *p); + +#define DEFINE_MEMPOOL(pool_name, tile_type, alloc_at_least) \ +struct mempool pool_name = { \ + .tile_size = sizeof(tile_type), \ + .at_least = alloc_at_least, \ +} + + +#ifdef VALGRIND +void mempool_drop(struct mempool *mp); +#endif diff --git a/src/systemd/src/basic/parse-util.c b/src/systemd/src/basic/parse-util.c new file mode 100644 index 00000000..86aec95c --- /dev/null +++ b/src/systemd/src/basic/parse-util.c @@ -0,0 +1,542 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "alloc-util.h" +#if 0 /* NM_IGNORED */ +#include "extract-word.h" +#endif /* NM_IGNORED */ +#include "macro.h" +#include "parse-util.h" +#include "string-util.h" + +int parse_boolean(const char *v) { + assert(v); + + if (streq(v, "1") || strcaseeq(v, "yes") || strcaseeq(v, "y") || strcaseeq(v, "true") || strcaseeq(v, "t") || strcaseeq(v, "on")) + return 1; + else if (streq(v, "0") || strcaseeq(v, "no") || strcaseeq(v, "n") || strcaseeq(v, "false") || strcaseeq(v, "f") || strcaseeq(v, "off")) + return 0; + + return -EINVAL; +} + +int parse_pid(const char *s, pid_t* ret_pid) { + unsigned long ul = 0; + pid_t pid; + int r; + + assert(s); + assert(ret_pid); + + r = safe_atolu(s, &ul); + if (r < 0) + return r; + + pid = (pid_t) ul; + + if ((unsigned long) pid != ul) + return -ERANGE; + + if (pid <= 0) + return -ERANGE; + + *ret_pid = pid; + return 0; +} + +int parse_mode(const char *s, mode_t *ret) { + char *x; + long l; + + assert(s); + assert(ret); + + s += strspn(s, WHITESPACE); + if (s[0] == '-') + return -ERANGE; + + errno = 0; + l = strtol(s, &x, 8); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (l < 0 || l > 07777) + return -ERANGE; + + *ret = (mode_t) l; + return 0; +} + +int parse_ifindex(const char *s, int *ret) { + int ifi, r; + + r = safe_atoi(s, &ifi); + if (r < 0) + return r; + if (ifi <= 0) + return -EINVAL; + + *ret = ifi; + return 0; +} + +int parse_size(const char *t, uint64_t base, uint64_t *size) { + + /* Soo, sometimes we want to parse IEC binary suffixes, and + * sometimes SI decimal suffixes. This function can parse + * both. Which one is the right way depends on the + * context. Wikipedia suggests that SI is customary for + * hardware metrics and network speeds, while IEC is + * customary for most data sizes used by software and volatile + * (RAM) memory. Hence be careful which one you pick! + * + * In either case we use just K, M, G as suffix, and not Ki, + * Mi, Gi or so (as IEC would suggest). That's because that's + * frickin' ugly. But this means you really need to make sure + * to document which base you are parsing when you use this + * call. */ + + struct table { + const char *suffix; + unsigned long long factor; + }; + + static const struct table iec[] = { + { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, + { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL }, + { "T", 1024ULL*1024ULL*1024ULL*1024ULL }, + { "G", 1024ULL*1024ULL*1024ULL }, + { "M", 1024ULL*1024ULL }, + { "K", 1024ULL }, + { "B", 1ULL }, + { "", 1ULL }, + }; + + static const struct table si[] = { + { "E", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, + { "P", 1000ULL*1000ULL*1000ULL*1000ULL*1000ULL }, + { "T", 1000ULL*1000ULL*1000ULL*1000ULL }, + { "G", 1000ULL*1000ULL*1000ULL }, + { "M", 1000ULL*1000ULL }, + { "K", 1000ULL }, + { "B", 1ULL }, + { "", 1ULL }, + }; + + const struct table *table; + const char *p; + unsigned long long r = 0; + unsigned n_entries, start_pos = 0; + + assert(t); + assert(base == 1000 || base == 1024); + assert(size); + + if (base == 1000) { + table = si; + n_entries = ELEMENTSOF(si); + } else { + table = iec; + n_entries = ELEMENTSOF(iec); + } + + p = t; + do { + unsigned long long l, tmp; + double frac = 0; + char *e; + unsigned i; + + p += strspn(p, WHITESPACE); + + errno = 0; + l = strtoull(p, &e, 10); + if (errno != 0) + return -errno; + if (e == p) + return -EINVAL; + if (*p == '-') + return -ERANGE; + + if (*e == '.') { + e++; + + /* strtoull() itself would accept space/+/- */ + if (*e >= '0' && *e <= '9') { + unsigned long long l2; + char *e2; + + l2 = strtoull(e, &e2, 10); + if (errno != 0) + return -errno; + + /* Ignore failure. E.g. 10.M is valid */ + frac = l2; + for (; e < e2; e++) + frac /= 10; + } + } + + e += strspn(e, WHITESPACE); + + for (i = start_pos; i < n_entries; i++) + if (startswith(e, table[i].suffix)) + break; + + if (i >= n_entries) + return -EINVAL; + + if (l + (frac > 0) > ULLONG_MAX / table[i].factor) + return -ERANGE; + + tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor); + if (tmp > ULLONG_MAX - r) + return -ERANGE; + + r += tmp; + if ((unsigned long long) (uint64_t) r != r) + return -ERANGE; + + p = e + strlen(table[i].suffix); + + start_pos = i + 1; + + } while (*p); + + *size = r; + + return 0; +} + +#if 0 /* NM_IGNORED */ +int parse_range(const char *t, unsigned *lower, unsigned *upper) { + _cleanup_free_ char *word = NULL; + unsigned l, u; + int r; + + assert(lower); + assert(upper); + + /* Extract the lower bound. */ + r = extract_first_word(&t, &word, "-", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + + r = safe_atou(word, &l); + if (r < 0) + return r; + + /* Check for the upper bound and extract it if needed */ + if (!t) + /* Single number with no dashes. */ + u = l; + else if (!*t) + /* Trailing dash is an error. */ + return -EINVAL; + else { + r = safe_atou(t, &u); + if (r < 0) + return r; + } + + *lower = l; + *upper = u; + return 0; +} +#endif /* NM_IGNORED */ + +char *format_bytes(char *buf, size_t l, uint64_t t) { + unsigned i; + + /* This only does IEC units so far */ + + static const struct { + const char *suffix; + uint64_t factor; + } table[] = { + { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) }, + { "M", UINT64_C(1024)*UINT64_C(1024) }, + { "K", UINT64_C(1024) }, + }; + + if (t == (uint64_t) -1) + return NULL; + + for (i = 0; i < ELEMENTSOF(table); i++) { + + if (t >= table[i].factor) { + snprintf(buf, l, + "%" PRIu64 ".%" PRIu64 "%s", + t / table[i].factor, + ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10), + table[i].suffix); + + goto finish; + } + } + + snprintf(buf, l, "%" PRIu64 "B", t); + +finish: + buf[l-1] = 0; + return buf; + +} + +int safe_atou(const char *s, unsigned *ret_u) { + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret_u); + + /* strtoul() is happy to parse negative values, and silently + * converts them to unsigned values without generating an + * error. We want a clean error, hence let's look for the "-" + * prefix on our own, and generate an error. But let's do so + * only after strtoul() validated that the string is clean + * otherwise, so that we return EINVAL preferably over + * ERANGE. */ + + s += strspn(s, WHITESPACE); + + errno = 0; + l = strtoul(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (s[0] == '-') + return -ERANGE; + if ((unsigned long) (unsigned) l != l) + return -ERANGE; + + *ret_u = (unsigned) l; + return 0; +} + +int safe_atoi(const char *s, int *ret_i) { + char *x = NULL; + long l; + + assert(s); + assert(ret_i); + + errno = 0; + l = strtol(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if ((long) (int) l != l) + return -ERANGE; + + *ret_i = (int) l; + return 0; +} + +int safe_atollu(const char *s, long long unsigned *ret_llu) { + char *x = NULL; + unsigned long long l; + + assert(s); + assert(ret_llu); + + s += strspn(s, WHITESPACE); + + errno = 0; + l = strtoull(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (*s == '-') + return -ERANGE; + + *ret_llu = l; + return 0; +} + +int safe_atolli(const char *s, long long int *ret_lli) { + char *x = NULL; + long long l; + + assert(s); + assert(ret_lli); + + errno = 0; + l = strtoll(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + + *ret_lli = l; + return 0; +} + +int safe_atou8(const char *s, uint8_t *ret) { + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret); + + s += strspn(s, WHITESPACE); + + errno = 0; + l = strtoul(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (s[0] == '-') + return -ERANGE; + if ((unsigned long) (uint8_t) l != l) + return -ERANGE; + + *ret = (uint8_t) l; + return 0; +} + +int safe_atou16(const char *s, uint16_t *ret) { + char *x = NULL; + unsigned long l; + + assert(s); + assert(ret); + + s += strspn(s, WHITESPACE); + + errno = 0; + l = strtoul(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if (s[0] == '-') + return -ERANGE; + if ((unsigned long) (uint16_t) l != l) + return -ERANGE; + + *ret = (uint16_t) l; + return 0; +} + +int safe_atoi16(const char *s, int16_t *ret) { + char *x = NULL; + long l; + + assert(s); + assert(ret); + + errno = 0; + l = strtol(s, &x, 0); + if (errno != 0) + return -errno; + if (!x || x == s || *x) + return -EINVAL; + if ((long) (int16_t) l != l) + return -ERANGE; + + *ret = (int16_t) l; + return 0; +} + +int safe_atod(const char *s, double *ret_d) { + char *x = NULL; + double d = 0; + locale_t loc; + + assert(s); + assert(ret_d); + + loc = newlocale(LC_NUMERIC_MASK, "C", (locale_t) 0); + if (loc == (locale_t) 0) + return -errno; + + errno = 0; + d = strtod_l(s, &x, loc); + if (errno != 0) { + freelocale(loc); + return -errno; + } + if (!x || x == s || *x) { + freelocale(loc); + return -EINVAL; + } + + freelocale(loc); + *ret_d = (double) d; + return 0; +} + +int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) { + size_t i; + unsigned val = 0; + const char *s; + + s = *p; + + /* accept any number of digits, strtoull is limted to 19 */ + for(i=0; i < digits; i++,s++) { + if (*s < '0' || *s > '9') { + if (i == 0) + return -EINVAL; + + /* too few digits, pad with 0 */ + for (; i < digits; i++) + val *= 10; + + break; + } + + val *= 10; + val += *s - '0'; + } + + /* maybe round up */ + if (*s >= '5' && *s <= '9') + val++; + + s += strspn(s, DIGITS); + + *p = s; + *res = val; + + return 0; +} diff --git a/src/systemd/src/basic/parse-util.h b/src/systemd/src/basic/parse-util.h new file mode 100644 index 00000000..fbdf1e43 --- /dev/null +++ b/src/systemd/src/basic/parse-util.h @@ -0,0 +1,99 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include + +#include "macro.h" + +#define MODE_INVALID ((mode_t) -1) + +int parse_boolean(const char *v) _pure_; +int parse_pid(const char *s, pid_t* ret_pid); +int parse_mode(const char *s, mode_t *ret); +int parse_ifindex(const char *s, int *ret); + +int parse_size(const char *t, uint64_t base, uint64_t *size); +int parse_range(const char *t, unsigned *lower, unsigned *upper); + +#define FORMAT_BYTES_MAX 8 +char *format_bytes(char *buf, size_t l, uint64_t t); + +int safe_atou(const char *s, unsigned *ret_u); +int safe_atoi(const char *s, int *ret_i); +int safe_atollu(const char *s, unsigned long long *ret_u); +int safe_atolli(const char *s, long long int *ret_i); + +int safe_atou8(const char *s, uint8_t *ret); + +int safe_atou16(const char *s, uint16_t *ret); +int safe_atoi16(const char *s, int16_t *ret); + +static inline int safe_atou32(const char *s, uint32_t *ret_u) { + assert_cc(sizeof(uint32_t) == sizeof(unsigned)); + return safe_atou(s, (unsigned*) ret_u); +} + +static inline int safe_atoi32(const char *s, int32_t *ret_i) { + assert_cc(sizeof(int32_t) == sizeof(int)); + return safe_atoi(s, (int*) ret_i); +} + +static inline int safe_atou64(const char *s, uint64_t *ret_u) { + assert_cc(sizeof(uint64_t) == sizeof(unsigned long long)); + return safe_atollu(s, (unsigned long long*) ret_u); +} + +static inline int safe_atoi64(const char *s, int64_t *ret_i) { + assert_cc(sizeof(int64_t) == sizeof(long long int)); + return safe_atolli(s, (long long int*) ret_i); +} + +#if LONG_MAX == INT_MAX +static inline int safe_atolu(const char *s, unsigned long *ret_u) { + assert_cc(sizeof(unsigned long) == sizeof(unsigned)); + return safe_atou(s, (unsigned*) ret_u); +} +static inline int safe_atoli(const char *s, long int *ret_u) { + assert_cc(sizeof(long int) == sizeof(int)); + return safe_atoi(s, (int*) ret_u); +} +#else +static inline int safe_atolu(const char *s, unsigned long *ret_u) { + assert_cc(sizeof(unsigned long) == sizeof(unsigned long long)); + return safe_atollu(s, (unsigned long long*) ret_u); +} +static inline int safe_atoli(const char *s, long int *ret_u) { + assert_cc(sizeof(long int) == sizeof(long long int)); + return safe_atolli(s, (long long int*) ret_u); +} +#endif + +int safe_atod(const char *s, double *ret_d); + +int parse_fractional_part_u(const char **s, size_t digits, unsigned *res); diff --git a/src/systemd/src/basic/path-util.c b/src/systemd/src/basic/path-util.c new file mode 100644 index 00000000..14dc35db --- /dev/null +++ b/src/systemd/src/basic/path-util.c @@ -0,0 +1,813 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include +#include + +/* When we include libgen.h because we need dirname() we immediately + * undefine basename() since libgen.h defines it as a macro to the + * POSIX version which is really broken. We prefer GNU basename(). */ +#include +#undef basename + +#include "alloc-util.h" +#if 0 /* NM_IGNORED */ +#include "extract-word.h" +#endif /* NM_IGNORED */ +#include "fs-util.h" +#include "log.h" +#include "macro.h" +#if 0 /* NM_IGNORED */ +#include "missing.h" +#endif /* NM_IGNORED */ +#include "path-util.h" +#if 0 /* NM_IGNORED */ +#include "stat-util.h" +#endif /* NM_IGNORED */ +#include "string-util.h" +#include "strv.h" +#include "time-util.h" + +#if 0 /* NM_IGNORED */ +bool path_is_absolute(const char *p) { + return p[0] == '/'; +} + +bool is_path(const char *p) { + return !!strchr(p, '/'); +} + +int path_split_and_make_absolute(const char *p, char ***ret) { + char **l; + int r; + + assert(p); + assert(ret); + + l = strv_split(p, ":"); + if (!l) + return -ENOMEM; + + r = path_strv_make_absolute_cwd(l); + if (r < 0) { + strv_free(l); + return r; + } + + *ret = l; + return r; +} + +char *path_make_absolute(const char *p, const char *prefix) { + assert(p); + + /* Makes every item in the list an absolute path by prepending + * the prefix, if specified and necessary */ + + if (path_is_absolute(p) || !prefix) + return strdup(p); + + return strjoin(prefix, "/", p, NULL); +} + +int path_make_absolute_cwd(const char *p, char **ret) { + char *c; + + assert(p); + assert(ret); + + /* Similar to path_make_absolute(), but prefixes with the + * current working directory. */ + + if (path_is_absolute(p)) + c = strdup(p); + else { + _cleanup_free_ char *cwd = NULL; + + cwd = get_current_dir_name(); + if (!cwd) + return -errno; + + c = strjoin(cwd, "/", p, NULL); + } + if (!c) + return -ENOMEM; + + *ret = c; + return 0; +} + +int path_make_relative(const char *from_dir, const char *to_path, char **_r) { + char *r, *p; + unsigned n_parents; + + assert(from_dir); + assert(to_path); + assert(_r); + + /* Strips the common part, and adds ".." elements as necessary. */ + + if (!path_is_absolute(from_dir)) + return -EINVAL; + + if (!path_is_absolute(to_path)) + return -EINVAL; + + /* Skip the common part. */ + for (;;) { + size_t a; + size_t b; + + from_dir += strspn(from_dir, "/"); + to_path += strspn(to_path, "/"); + + if (!*from_dir) { + if (!*to_path) + /* from_dir equals to_path. */ + r = strdup("."); + else + /* from_dir is a parent directory of to_path. */ + r = strdup(to_path); + + if (!r) + return -ENOMEM; + + path_kill_slashes(r); + + *_r = r; + return 0; + } + + if (!*to_path) + break; + + a = strcspn(from_dir, "/"); + b = strcspn(to_path, "/"); + + if (a != b) + break; + + if (memcmp(from_dir, to_path, a) != 0) + break; + + from_dir += a; + to_path += b; + } + + /* If we're here, then "from_dir" has one or more elements that need to + * be replaced with "..". */ + + /* Count the number of necessary ".." elements. */ + for (n_parents = 0;;) { + from_dir += strspn(from_dir, "/"); + + if (!*from_dir) + break; + + from_dir += strcspn(from_dir, "/"); + n_parents++; + } + + r = malloc(n_parents * 3 + strlen(to_path) + 1); + if (!r) + return -ENOMEM; + + for (p = r; n_parents > 0; n_parents--, p += 3) + memcpy(p, "../", 3); + + strcpy(p, to_path); + path_kill_slashes(r); + + *_r = r; + return 0; +} + +int path_strv_make_absolute_cwd(char **l) { + char **s; + int r; + + /* Goes through every item in the string list and makes it + * absolute. This works in place and won't rollback any + * changes on failure. */ + + STRV_FOREACH(s, l) { + char *t; + + r = path_make_absolute_cwd(*s, &t); + if (r < 0) + return r; + + free(*s); + *s = t; + } + + return 0; +} + +char **path_strv_resolve(char **l, const char *prefix) { + char **s; + unsigned k = 0; + bool enomem = false; + + if (strv_isempty(l)) + return l; + + /* Goes through every item in the string list and canonicalize + * the path. This works in place and won't rollback any + * changes on failure. */ + + STRV_FOREACH(s, l) { + char *t, *u; + _cleanup_free_ char *orig = NULL; + + if (!path_is_absolute(*s)) { + free(*s); + continue; + } + + if (prefix) { + orig = *s; + t = strappend(prefix, orig); + if (!t) { + enomem = true; + continue; + } + } else + t = *s; + + errno = 0; + u = canonicalize_file_name(t); + if (!u) { + if (errno == ENOENT) { + if (prefix) { + u = orig; + orig = NULL; + free(t); + } else + u = t; + } else { + free(t); + if (errno == ENOMEM || errno == 0) + enomem = true; + + continue; + } + } else if (prefix) { + char *x; + + free(t); + x = path_startswith(u, prefix); + if (x) { + /* restore the slash if it was lost */ + if (!startswith(x, "/")) + *(--x) = '/'; + + t = strdup(x); + free(u); + if (!t) { + enomem = true; + continue; + } + u = t; + } else { + /* canonicalized path goes outside of + * prefix, keep the original path instead */ + free(u); + u = orig; + orig = NULL; + } + } else + free(t); + + l[k++] = u; + } + + l[k] = NULL; + + if (enomem) + return NULL; + + return l; +} + +char **path_strv_resolve_uniq(char **l, const char *prefix) { + + if (strv_isempty(l)) + return l; + + if (!path_strv_resolve(l, prefix)) + return NULL; + + return strv_uniq(l); +} +#endif /* NM_IGNORED */ + +char *path_kill_slashes(char *path) { + char *f, *t; + bool slash = false; + + /* Removes redundant inner and trailing slashes. Modifies the + * passed string in-place. + * + * ///foo///bar/ becomes /foo/bar + */ + + for (f = path, t = path; *f; f++) { + + if (*f == '/') { + slash = true; + continue; + } + + if (slash) { + slash = false; + *(t++) = '/'; + } + + *(t++) = *f; + } + + /* Special rule, if we are talking of the root directory, a + trailing slash is good */ + + if (t == path && slash) + *(t++) = '/'; + + *t = 0; + return path; +} + +#if 0 /* NM_IGNORED */ +char* path_startswith(const char *path, const char *prefix) { + assert(path); + assert(prefix); + + if ((path[0] == '/') != (prefix[0] == '/')) + return NULL; + + for (;;) { + size_t a, b; + + path += strspn(path, "/"); + prefix += strspn(prefix, "/"); + + if (*prefix == 0) + return (char*) path; + + if (*path == 0) + return NULL; + + a = strcspn(path, "/"); + b = strcspn(prefix, "/"); + + if (a != b) + return NULL; + + if (memcmp(path, prefix, a) != 0) + return NULL; + + path += a; + prefix += b; + } +} + +int path_compare(const char *a, const char *b) { + int d; + + assert(a); + assert(b); + + /* A relative path and an abolute path must not compare as equal. + * Which one is sorted before the other does not really matter. + * Here a relative path is ordered before an absolute path. */ + d = (a[0] == '/') - (b[0] == '/'); + if (d != 0) + return d; + + for (;;) { + size_t j, k; + + a += strspn(a, "/"); + b += strspn(b, "/"); + + if (*a == 0 && *b == 0) + return 0; + + /* Order prefixes first: "/foo" before "/foo/bar" */ + if (*a == 0) + return -1; + if (*b == 0) + return 1; + + j = strcspn(a, "/"); + k = strcspn(b, "/"); + + /* Alphabetical sort: "/foo/aaa" before "/foo/b" */ + d = memcmp(a, b, MIN(j, k)); + if (d != 0) + return (d > 0) - (d < 0); /* sign of d */ + + /* Sort "/foo/a" before "/foo/aaa" */ + d = (j > k) - (j < k); /* sign of (j - k) */ + if (d != 0) + return d; + + a += j; + b += k; + } +} + +bool path_equal(const char *a, const char *b) { + return path_compare(a, b) == 0; +} + +bool path_equal_or_files_same(const char *a, const char *b) { + return path_equal(a, b) || files_same(a, b) > 0; +} + +char* path_join(const char *root, const char *path, const char *rest) { + assert(path); + + if (!isempty(root)) + return strjoin(root, endswith(root, "/") ? "" : "/", + path[0] == '/' ? path+1 : path, + rest ? (endswith(path, "/") ? "" : "/") : NULL, + rest && rest[0] == '/' ? rest+1 : rest, + NULL); + else + return strjoin(path, + rest ? (endswith(path, "/") ? "" : "/") : NULL, + rest && rest[0] == '/' ? rest+1 : rest, + NULL); +} + +int find_binary(const char *name, char **ret) { + int last_error, r; + const char *p; + + assert(name); + + if (is_path(name)) { + if (access(name, X_OK) < 0) + return -errno; + + if (ret) { + r = path_make_absolute_cwd(name, ret); + if (r < 0) + return r; + } + + return 0; + } + + /** + * Plain getenv, not secure_getenv, because we want + * to actually allow the user to pick the binary. + */ + p = getenv("PATH"); + if (!p) + p = DEFAULT_PATH; + + last_error = -ENOENT; + + for (;;) { + _cleanup_free_ char *j = NULL, *element = NULL; + + r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0) + break; + + if (!path_is_absolute(element)) + continue; + + j = strjoin(element, "/", name, NULL); + if (!j) + return -ENOMEM; + + if (access(j, X_OK) >= 0) { + /* Found it! */ + + if (ret) { + *ret = path_kill_slashes(j); + j = NULL; + } + + return 0; + } + + last_error = -errno; + } + + return last_error; +} + +bool paths_check_timestamp(const char* const* paths, usec_t *timestamp, bool update) { + bool changed = false; + const char* const* i; + + assert(timestamp); + + if (paths == NULL) + return false; + + STRV_FOREACH(i, paths) { + struct stat stats; + usec_t u; + + if (stat(*i, &stats) < 0) + continue; + + u = timespec_load(&stats.st_mtim); + + /* first check */ + if (*timestamp >= u) + continue; + + log_debug("timestamp of '%s' changed", *i); + + /* update timestamp */ + if (update) { + *timestamp = u; + changed = true; + } else + return true; + } + + return changed; +} + +static int binary_is_good(const char *binary) { + _cleanup_free_ char *p = NULL, *d = NULL; + int r; + + r = find_binary(binary, &p); + if (r == -ENOENT) + return 0; + if (r < 0) + return r; + + /* An fsck that is linked to /bin/true is a non-existent + * fsck */ + + r = readlink_malloc(p, &d); + if (r == -EINVAL) /* not a symlink */ + return 1; + if (r < 0) + return r; + + return !path_equal(d, "true") && + !path_equal(d, "/bin/true") && + !path_equal(d, "/usr/bin/true") && + !path_equal(d, "/dev/null"); +} + +int fsck_exists(const char *fstype) { + const char *checker; + + assert(fstype); + + if (streq(fstype, "auto")) + return -EINVAL; + + checker = strjoina("fsck.", fstype); + return binary_is_good(checker); +} + +int mkfs_exists(const char *fstype) { + const char *mkfs; + + assert(fstype); + + if (streq(fstype, "auto")) + return -EINVAL; + + mkfs = strjoina("mkfs.", fstype); + return binary_is_good(mkfs); +} + +char *prefix_root(const char *root, const char *path) { + char *n, *p; + size_t l; + + /* If root is passed, prefixes path with it. Otherwise returns + * it as is. */ + + assert(path); + + /* First, drop duplicate prefixing slashes from the path */ + while (path[0] == '/' && path[1] == '/') + path++; + + if (isempty(root) || path_equal(root, "/")) + return strdup(path); + + l = strlen(root) + 1 + strlen(path) + 1; + + n = new(char, l); + if (!n) + return NULL; + + p = stpcpy(n, root); + + while (p > n && p[-1] == '/') + p--; + + if (path[0] != '/') + *(p++) = '/'; + + strcpy(p, path); + return n; +} + +int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) { + char *p; + int r; + + /* + * This function is intended to be used in command line + * parsers, to handle paths that are passed in. It makes the + * path absolute, and reduces it to NULL if omitted or + * root (the latter optionally). + * + * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON + * SUCCESS! Hence, do not pass in uninitialized pointers. + */ + + if (isempty(path)) { + *arg = mfree(*arg); + return 0; + } + + r = path_make_absolute_cwd(path, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path); + + path_kill_slashes(p); + if (suppress_root && path_equal(p, "/")) + p = mfree(p); + + free(*arg); + *arg = p; + return 0; +} + +char* dirname_malloc(const char *path) { + char *d, *dir, *dir2; + + assert(path); + + d = strdup(path); + if (!d) + return NULL; + + dir = dirname(d); + assert(dir); + + if (dir == d) + return d; + + dir2 = strdup(dir); + free(d); + + return dir2; +} +#endif /* NM_IGNORED */ + +bool filename_is_valid(const char *p) { + const char *e; + + if (isempty(p)) + return false; + + if (streq(p, ".")) + return false; + + if (streq(p, "..")) + return false; + + e = strchrnul(p, '/'); + if (*e != 0) + return false; + + if (e - p > FILENAME_MAX) + return false; + + return true; +} + +#if 0 /* NM_IGNORED */ +bool path_is_safe(const char *p) { + + if (isempty(p)) + return false; + + if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../")) + return false; + + if (strlen(p)+1 > PATH_MAX) + return false; + + /* The following two checks are not really dangerous, but hey, they still are confusing */ + if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./")) + return false; + + if (strstr(p, "//")) + return false; + + return true; +} + +char *file_in_same_dir(const char *path, const char *filename) { + char *e, *ret; + size_t k; + + assert(path); + assert(filename); + + /* This removes the last component of path and appends + * filename, unless the latter is absolute anyway or the + * former isn't */ + + if (path_is_absolute(filename)) + return strdup(filename); + + e = strrchr(path, '/'); + if (!e) + return strdup(filename); + + k = strlen(filename); + ret = new(char, (e + 1 - path) + k + 1); + if (!ret) + return NULL; + + memcpy(mempcpy(ret, path, e + 1 - path), filename, k + 1); + return ret; +} + +bool hidden_file_allow_backup(const char *filename) { + assert(filename); + + return + filename[0] == '.' || + streq(filename, "lost+found") || + streq(filename, "aquota.user") || + streq(filename, "aquota.group") || + endswith(filename, ".rpmnew") || + endswith(filename, ".rpmsave") || + endswith(filename, ".rpmorig") || + endswith(filename, ".dpkg-old") || + endswith(filename, ".dpkg-new") || + endswith(filename, ".dpkg-tmp") || + endswith(filename, ".dpkg-dist") || + endswith(filename, ".dpkg-bak") || + endswith(filename, ".dpkg-backup") || + endswith(filename, ".dpkg-remove") || + endswith(filename, ".swp"); +} + +bool hidden_file(const char *filename) { + assert(filename); + + if (endswith(filename, "~")) + return true; + + return hidden_file_allow_backup(filename); +} + +bool is_device_path(const char *path) { + + /* Returns true on paths that refer to a device, either in + * sysfs or in /dev */ + + return + path_startswith(path, "/dev/") || + path_startswith(path, "/sys/"); +} +#endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/path-util.h b/src/systemd/src/basic/path-util.h new file mode 100644 index 00000000..2bc23fec --- /dev/null +++ b/src/systemd/src/basic/path-util.h @@ -0,0 +1,115 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010-2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include + +#include "macro.h" +#include "time-util.h" + +#define DEFAULT_PATH_NORMAL "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin" +#define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":/sbin:/bin" + +#ifdef HAVE_SPLIT_USR +# define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR +#else +# define DEFAULT_PATH DEFAULT_PATH_NORMAL +#endif + +bool is_path(const char *p) _pure_; +int path_split_and_make_absolute(const char *p, char ***ret); +bool path_is_absolute(const char *p) _pure_; +char* path_make_absolute(const char *p, const char *prefix); +int path_make_absolute_cwd(const char *p, char **ret); +int path_make_relative(const char *from_dir, const char *to_path, char **_r); +char* path_kill_slashes(char *path); +char* path_startswith(const char *path, const char *prefix) _pure_; +int path_compare(const char *a, const char *b) _pure_; +bool path_equal(const char *a, const char *b) _pure_; +bool path_equal_or_files_same(const char *a, const char *b); +char* path_join(const char *root, const char *path, const char *rest); + +int path_strv_make_absolute_cwd(char **l); +char** path_strv_resolve(char **l, const char *prefix); +char** path_strv_resolve_uniq(char **l, const char *prefix); + +int find_binary(const char *name, char **filename); + +bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update); + +int fsck_exists(const char *fstype); +int mkfs_exists(const char *fstype); + +/* Iterates through the path prefixes of the specified path, going up + * the tree, to root. Also returns "" (and not "/"!) for the root + * directory. Excludes the specified directory itself */ +#define PATH_FOREACH_PREFIX(prefix, path) \ + for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) + +/* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */ +#define PATH_FOREACH_PREFIX_MORE(prefix, path) \ + for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/')) + +char *prefix_root(const char *root, const char *path); + +/* Similar to prefix_root(), but returns an alloca() buffer, or + * possibly a const pointer into the path parameter */ +#define prefix_roota(root, path) \ + ({ \ + const char* _path = (path), *_root = (root), *_ret; \ + char *_p, *_n; \ + size_t _l; \ + while (_path[0] == '/' && _path[1] == '/') \ + _path ++; \ + if (isempty(_root) || path_equal(_root, "/")) \ + _ret = _path; \ + else { \ + _l = strlen(_root) + 1 + strlen(_path) + 1; \ + _n = alloca(_l); \ + _p = stpcpy(_n, _root); \ + while (_p > _n && _p[-1] == '/') \ + _p--; \ + if (_path[0] != '/') \ + *(_p++) = '/'; \ + strcpy(_p, _path); \ + _ret = _n; \ + } \ + _ret; \ + }) + +int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg); + +char* dirname_malloc(const char *path); + +bool filename_is_valid(const char *p) _pure_; +bool path_is_safe(const char *p) _pure_; + +char *file_in_same_dir(const char *path, const char *filename); + +bool hidden_file_allow_backup(const char *filename); +bool hidden_file(const char *filename) _pure_; + +bool is_device_path(const char *path); diff --git a/src/systemd/src/basic/prioq.c b/src/systemd/src/basic/prioq.c new file mode 100644 index 00000000..4be4ad6e --- /dev/null +++ b/src/systemd/src/basic/prioq.c @@ -0,0 +1,324 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +/* + * Priority Queue + * The prioq object implements a priority queue. That is, it orders objects by + * their priority and allows O(1) access to the object with the highest + * priority. Insertion and removal are Θ(log n). Optionally, the caller can + * provide a pointer to an index which will be kept up-to-date by the prioq. + * + * The underlying algorithm used in this implementation is a Heap. + */ + +#include "nm-sd-adapt.h" + +#include +#include + +#include "alloc-util.h" +#include "hashmap.h" +#include "prioq.h" + +struct prioq_item { + void *data; + unsigned *idx; +}; + +struct Prioq { + compare_func_t compare_func; + unsigned n_items, n_allocated; + + struct prioq_item *items; +}; + +Prioq *prioq_new(compare_func_t compare_func) { + Prioq *q; + + q = new0(Prioq, 1); + if (!q) + return q; + + q->compare_func = compare_func; + return q; +} + +Prioq* prioq_free(Prioq *q) { + if (!q) + return NULL; + + free(q->items); + free(q); + + return NULL; +} + +int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func) { + assert(q); + + if (*q) + return 0; + + *q = prioq_new(compare_func); + if (!*q) + return -ENOMEM; + + return 0; +} + +static void swap(Prioq *q, unsigned j, unsigned k) { + void *saved_data; + unsigned *saved_idx; + + assert(q); + assert(j < q->n_items); + assert(k < q->n_items); + + assert(!q->items[j].idx || *(q->items[j].idx) == j); + assert(!q->items[k].idx || *(q->items[k].idx) == k); + + saved_data = q->items[j].data; + saved_idx = q->items[j].idx; + q->items[j].data = q->items[k].data; + q->items[j].idx = q->items[k].idx; + q->items[k].data = saved_data; + q->items[k].idx = saved_idx; + + if (q->items[j].idx) + *q->items[j].idx = j; + + if (q->items[k].idx) + *q->items[k].idx = k; +} + +static unsigned shuffle_up(Prioq *q, unsigned idx) { + assert(q); + + while (idx > 0) { + unsigned k; + + k = (idx-1)/2; + + if (q->compare_func(q->items[k].data, q->items[idx].data) <= 0) + break; + + swap(q, idx, k); + idx = k; + } + + return idx; +} + +static unsigned shuffle_down(Prioq *q, unsigned idx) { + assert(q); + + for (;;) { + unsigned j, k, s; + + k = (idx+1)*2; /* right child */ + j = k-1; /* left child */ + + if (j >= q->n_items) + break; + + if (q->compare_func(q->items[j].data, q->items[idx].data) < 0) + + /* So our left child is smaller than we are, let's + * remember this fact */ + s = j; + else + s = idx; + + if (k < q->n_items && + q->compare_func(q->items[k].data, q->items[s].data) < 0) + + /* So our right child is smaller than we are, let's + * remember this fact */ + s = k; + + /* s now points to the smallest of the three items */ + + if (s == idx) + /* No swap necessary, we're done */ + break; + + swap(q, idx, s); + idx = s; + } + + return idx; +} + +int prioq_put(Prioq *q, void *data, unsigned *idx) { + struct prioq_item *i; + unsigned k; + + assert(q); + + if (q->n_items >= q->n_allocated) { + unsigned n; + struct prioq_item *j; + + n = MAX((q->n_items+1) * 2, 16u); + j = realloc(q->items, sizeof(struct prioq_item) * n); + if (!j) + return -ENOMEM; + + q->items = j; + q->n_allocated = n; + } + + k = q->n_items++; + i = q->items + k; + i->data = data; + i->idx = idx; + + if (idx) + *idx = k; + + shuffle_up(q, k); + + return 0; +} + +static void remove_item(Prioq *q, struct prioq_item *i) { + struct prioq_item *l; + + assert(q); + assert(i); + + l = q->items + q->n_items - 1; + + if (i == l) + /* Last entry, let's just remove it */ + q->n_items--; + else { + unsigned k; + + /* Not last entry, let's replace the last entry with + * this one, and reshuffle */ + + k = i - q->items; + + i->data = l->data; + i->idx = l->idx; + if (i->idx) + *i->idx = k; + q->n_items--; + + k = shuffle_down(q, k); + shuffle_up(q, k); + } +} + +_pure_ static struct prioq_item* find_item(Prioq *q, void *data, unsigned *idx) { + struct prioq_item *i; + + assert(q); + + if (idx) { + if (*idx == PRIOQ_IDX_NULL || + *idx > q->n_items) + return NULL; + + i = q->items + *idx; + if (i->data != data) + return NULL; + + return i; + } else { + for (i = q->items; i < q->items + q->n_items; i++) + if (i->data == data) + return i; + return NULL; + } +} + +int prioq_remove(Prioq *q, void *data, unsigned *idx) { + struct prioq_item *i; + + if (!q) + return 0; + + i = find_item(q, data, idx); + if (!i) + return 0; + + remove_item(q, i); + return 1; +} + +int prioq_reshuffle(Prioq *q, void *data, unsigned *idx) { + struct prioq_item *i; + unsigned k; + + assert(q); + + i = find_item(q, data, idx); + if (!i) + return 0; + + k = i - q->items; + k = shuffle_down(q, k); + shuffle_up(q, k); + return 1; +} + +void *prioq_peek(Prioq *q) { + + if (!q) + return NULL; + + if (q->n_items <= 0) + return NULL; + + return q->items[0].data; +} + +void *prioq_pop(Prioq *q) { + void *data; + + if (!q) + return NULL; + + if (q->n_items <= 0) + return NULL; + + data = q->items[0].data; + remove_item(q, q->items); + return data; +} + +unsigned prioq_size(Prioq *q) { + + if (!q) + return 0; + + return q->n_items; +} + +bool prioq_isempty(Prioq *q) { + + if (!q) + return true; + + return q->n_items <= 0; +} diff --git a/src/systemd/src/basic/prioq.h b/src/systemd/src/basic/prioq.h new file mode 100644 index 00000000..f6a88f0a --- /dev/null +++ b/src/systemd/src/basic/prioq.h @@ -0,0 +1,47 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include + +#include "hashmap.h" +#include "macro.h" + +typedef struct Prioq Prioq; + +#define PRIOQ_IDX_NULL ((unsigned) -1) + +Prioq *prioq_new(compare_func_t compare); +Prioq *prioq_free(Prioq *q); +int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func); + +int prioq_put(Prioq *q, void *data, unsigned *idx); +int prioq_remove(Prioq *q, void *data, unsigned *idx); +int prioq_reshuffle(Prioq *q, void *data, unsigned *idx); + +void *prioq_peek(Prioq *q) _pure_; +void *prioq_pop(Prioq *q); + +unsigned prioq_size(Prioq *q) _pure_; +bool prioq_isempty(Prioq *q) _pure_; diff --git a/src/systemd/src/basic/random-util.c b/src/systemd/src/basic/random-util.c new file mode 100644 index 00000000..21d9bde7 --- /dev/null +++ b/src/systemd/src/basic/random-util.c @@ -0,0 +1,140 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_AUXV_H +#include +#endif + +#include "fd-util.h" +#include "io-util.h" +#if 0 /* NM_IGNORED */ +#include "missing.h" +#endif +#include "random-util.h" +#include "time-util.h" + +int dev_urandom(void *p, size_t n) { +#if 0 /* NM_IGNORED */ + static int have_syscall = -1; + + _cleanup_close_ int fd = -1; + int r; + + /* Gathers some randomness from the kernel. This call will + * never block, and will always return some data from the + * kernel, regardless if the random pool is fully initialized + * or not. It thus makes no guarantee for the quality of the + * returned entropy, but is good enough for or usual usecases + * of seeding the hash functions for hashtable */ + + /* Use the getrandom() syscall unless we know we don't have + * it, or when the requested size is too large for it. */ + if (have_syscall != 0 || (size_t) (int) n != n) { + r = getrandom(p, n, GRND_NONBLOCK); + if (r == (int) n) { + have_syscall = true; + return 0; + } + + if (r < 0) { + if (errno == ENOSYS) + /* we lack the syscall, continue with + * reading from /dev/urandom */ + have_syscall = false; + else if (errno == EAGAIN) + /* not enough entropy for now. Let's + * remember to use the syscall the + * next time, again, but also read + * from /dev/urandom for now, which + * doesn't care about the current + * amount of entropy. */ + have_syscall = true; + else + return -errno; + } else + /* too short read? */ + return -ENODATA; + } +#else /* NM_IGNORED */ + _cleanup_close_ int fd = -1; +#endif /* NM_IGNORED */ + + fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return errno == ENOENT ? -ENOSYS : -errno; + + return loop_read_exact(fd, p, n, true); +} + +void initialize_srand(void) { + static bool srand_called = false; + unsigned x; +#ifdef HAVE_SYS_AUXV_H + void *auxv; +#endif + + if (srand_called) + return; + + x = 0; + +#ifdef HAVE_SYS_AUXV_H + /* The kernel provides us with a bit of entropy in auxv, so + * let's try to make use of that to seed the pseudo-random + * generator. It's better than nothing... */ + + auxv = (void*) getauxval(AT_RANDOM); + if (auxv) + x ^= *(unsigned*) auxv; +#endif + + x ^= (unsigned) now(CLOCK_REALTIME); + x ^= (unsigned) gettid(); + + srand(x); + srand_called = true; +} + +void random_bytes(void *p, size_t n) { + uint8_t *q; + int r; + + r = dev_urandom(p, n); + if (r >= 0) + return; + + /* If some idiot made /dev/urandom unavailable to us, he'll + * get a PRNG instead. */ + + initialize_srand(); + + for (q = p; q < (uint8_t*) p + n; q ++) + *q = rand(); +} diff --git a/src/systemd/src/basic/random-util.h b/src/systemd/src/basic/random-util.h new file mode 100644 index 00000000..1ae76ef0 --- /dev/null +++ b/src/systemd/src/basic/random-util.h @@ -0,0 +1,41 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +int dev_urandom(void *p, size_t n); +void random_bytes(void *p, size_t n); +void initialize_srand(void); + +static inline uint64_t random_u64(void) { + uint64_t u; + random_bytes(&u, sizeof(u)); + return u; +} + +static inline uint32_t random_u32(void) { + uint32_t u; + random_bytes(&u, sizeof(u)); + return u; +} diff --git a/src/systemd/src/basic/refcnt.h b/src/systemd/src/basic/refcnt.h new file mode 100644 index 00000000..f7a26192 --- /dev/null +++ b/src/systemd/src/basic/refcnt.h @@ -0,0 +1,38 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +/* A type-safe atomic refcounter. + * + * DO NOT USE THIS UNLESS YOU ACTUALLY CARE ABOUT THREAD SAFETY! */ + +typedef struct { + volatile unsigned _value; +} RefCount; + +#define REFCNT_GET(r) ((r)._value) +#define REFCNT_INC(r) (__sync_add_and_fetch(&(r)._value, 1)) +#define REFCNT_DEC(r) (__sync_sub_and_fetch(&(r)._value, 1)) + +#define REFCNT_INIT ((RefCount) { ._value = 1 }) diff --git a/src/systemd/src/basic/set.h b/src/systemd/src/basic/set.h new file mode 100644 index 00000000..84c53888 --- /dev/null +++ b/src/systemd/src/basic/set.h @@ -0,0 +1,137 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include "hashmap.h" +#include "macro.h" + +Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +#define set_new(ops) internal_set_new(ops HASHMAP_DEBUG_SRC_ARGS) + +static inline Set *set_free(Set *s) { + internal_hashmap_free(HASHMAP_BASE(s)); + return NULL; +} + +static inline Set *set_free_free(Set *s) { + internal_hashmap_free_free(HASHMAP_BASE(s)); + return NULL; +} + +/* no set_free_free_free */ + +static inline Set *set_copy(Set *s) { + return (Set*) internal_hashmap_copy(HASHMAP_BASE(s)); +} + +int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +#define set_ensure_allocated(h, ops) internal_set_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) + +int set_put(Set *s, const void *key); +/* no set_update */ +/* no set_replace */ +static inline void *set_get(Set *s, void *key) { + return internal_hashmap_get(HASHMAP_BASE(s), key); +} +/* no set_get2 */ + +static inline bool set_contains(Set *s, const void *key) { + return internal_hashmap_contains(HASHMAP_BASE(s), key); +} + +static inline void *set_remove(Set *s, const void *key) { + return internal_hashmap_remove(HASHMAP_BASE(s), key); +} + +/* no set_remove2 */ +/* no set_remove_value */ +int set_remove_and_put(Set *s, const void *old_key, const void *new_key); +/* no set_remove_and_replace */ +int set_merge(Set *s, Set *other); + +static inline int set_reserve(Set *h, unsigned entries_add) { + return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add); +} + +static inline int set_move(Set *s, Set *other) { + return internal_hashmap_move(HASHMAP_BASE(s), HASHMAP_BASE(other)); +} + +static inline int set_move_one(Set *s, Set *other, const void *key) { + return internal_hashmap_move_one(HASHMAP_BASE(s), HASHMAP_BASE(other), key); +} + +static inline unsigned set_size(Set *s) { + return internal_hashmap_size(HASHMAP_BASE(s)); +} + +static inline bool set_isempty(Set *s) { + return set_size(s) == 0; +} + +static inline unsigned set_buckets(Set *s) { + return internal_hashmap_buckets(HASHMAP_BASE(s)); +} + +bool set_iterate(Set *s, Iterator *i, void **value); + +static inline void set_clear(Set *s) { + internal_hashmap_clear(HASHMAP_BASE(s)); +} + +static inline void set_clear_free(Set *s) { + internal_hashmap_clear_free(HASHMAP_BASE(s)); +} + +/* no set_clear_free_free */ + +static inline void *set_steal_first(Set *s) { + return internal_hashmap_steal_first(HASHMAP_BASE(s)); +} + +/* no set_steal_first_key */ +/* no set_first_key */ + +static inline void *set_first(Set *s) { + return internal_hashmap_first(HASHMAP_BASE(s)); +} + +/* no set_next */ + +static inline char **set_get_strv(Set *s) { + return internal_hashmap_get_strv(HASHMAP_BASE(s)); +} + +int set_consume(Set *s, void *value); +int set_put_strdup(Set *s, const char *p); +int set_put_strdupv(Set *s, char **l); + +#define SET_FOREACH(e, s, i) \ + for ((i) = ITERATOR_FIRST; set_iterate((s), &(i), (void**)&(e)); ) + +DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); + +#define _cleanup_set_free_ _cleanup_(set_freep) +#define _cleanup_set_free_free_ _cleanup_(set_free_freep) diff --git a/src/systemd/src/basic/siphash24.c b/src/systemd/src/basic/siphash24.c new file mode 100644 index 00000000..145f64b2 --- /dev/null +++ b/src/systemd/src/basic/siphash24.c @@ -0,0 +1,193 @@ +/* + SipHash reference C implementation + + Written in 2012 by + Jean-Philippe Aumasson + Daniel J. Bernstein + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . + + (Minimal changes made by Lennart Poettering, to make clean for inclusion in systemd) + (Refactored by Tom Gundersen to split up in several functions and follow systemd + coding style) +*/ + +#include "nm-sd-adapt.h" + +#include "macro.h" +#include "siphash24.h" +#include "unaligned.h" + +static inline uint64_t rotate_left(uint64_t x, uint8_t b) { + assert(b < 64); + + return (x << b) | (x >> (64 - b)); +} + +static inline void sipround(struct siphash *state) { + assert(state); + + state->v0 += state->v1; + state->v1 = rotate_left(state->v1, 13); + state->v1 ^= state->v0; + state->v0 = rotate_left(state->v0, 32); + state->v2 += state->v3; + state->v3 = rotate_left(state->v3, 16); + state->v3 ^= state->v2; + state->v0 += state->v3; + state->v3 = rotate_left(state->v3, 21); + state->v3 ^= state->v0; + state->v2 += state->v1; + state->v1 = rotate_left(state->v1, 17); + state->v1 ^= state->v2; + state->v2 = rotate_left(state->v2, 32); +} + +void siphash24_init(struct siphash *state, const uint8_t k[16]) { + uint64_t k0, k1; + + assert(state); + assert(k); + + k0 = unaligned_read_le64(k); + k1 = unaligned_read_le64(k + 8); + + *state = (struct siphash) { + /* "somepseudorandomlygeneratedbytes" */ + .v0 = 0x736f6d6570736575ULL ^ k0, + .v1 = 0x646f72616e646f6dULL ^ k1, + .v2 = 0x6c7967656e657261ULL ^ k0, + .v3 = 0x7465646279746573ULL ^ k1, + .padding = 0, + .inlen = 0, + }; +} + +void siphash24_compress(const void *_in, size_t inlen, struct siphash *state) { + + const uint8_t *in = _in; + const uint8_t *end = in + inlen; + size_t left = state->inlen & 7; + uint64_t m; + + assert(in); + assert(state); + + /* Update total length */ + state->inlen += inlen; + + /* If padding exists, fill it out */ + if (left > 0) { + for ( ; in < end && left < 8; in ++, left ++) + state->padding |= ((uint64_t) *in) << (left * 8); + + if (in == end && left < 8) + /* We did not have enough input to fill out the padding completely */ + return; + +#ifdef DEBUG + printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); + printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); + printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); + printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); + printf("(%3zu) compress padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t)state->padding); +#endif + + state->v3 ^= state->padding; + sipround(state); + sipround(state); + state->v0 ^= state->padding; + + state->padding = 0; + } + + end -= (state->inlen % sizeof(uint64_t)); + + for ( ; in < end; in += 8) { + m = unaligned_read_le64(in); +#ifdef DEBUG + printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); + printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); + printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); + printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); + printf("(%3zu) compress %08x %08x\n", state->inlen, (uint32_t) (m >> 32), (uint32_t) m); +#endif + state->v3 ^= m; + sipround(state); + sipround(state); + state->v0 ^= m; + } + + left = state->inlen & 7; + switch (left) { + case 7: + state->padding |= ((uint64_t) in[6]) << 48; + case 6: + state->padding |= ((uint64_t) in[5]) << 40; + case 5: + state->padding |= ((uint64_t) in[4]) << 32; + case 4: + state->padding |= ((uint64_t) in[3]) << 24; + case 3: + state->padding |= ((uint64_t) in[2]) << 16; + case 2: + state->padding |= ((uint64_t) in[1]) << 8; + case 1: + state->padding |= ((uint64_t) in[0]); + case 0: + break; + } +} + +uint64_t siphash24_finalize(struct siphash *state) { + uint64_t b; + + assert(state); + + b = state->padding | (((uint64_t) state->inlen) << 56); + +#ifdef DEBUG + printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); + printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); + printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); + printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); + printf("(%3zu) padding %08x %08x\n", state->inlen, (uint32_t) (state->padding >> 32), (uint32_t) state->padding); +#endif + + state->v3 ^= b; + sipround(state); + sipround(state); + state->v0 ^= b; + +#ifdef DEBUG + printf("(%3zu) v0 %08x %08x\n", state->inlen, (uint32_t) (state->v0 >> 32), (uint32_t) state->v0); + printf("(%3zu) v1 %08x %08x\n", state->inlen, (uint32_t) (state->v1 >> 32), (uint32_t) state->v1); + printf("(%3zu) v2 %08x %08x\n", state->inlen, (uint32_t) (state->v2 >> 32), (uint32_t) state->v2); + printf("(%3zu) v3 %08x %08x\n", state->inlen, (uint32_t) (state->v3 >> 32), (uint32_t) state->v3); +#endif + state->v2 ^= 0xff; + + sipround(state); + sipround(state); + sipround(state); + sipround(state); + + return state->v0 ^ state->v1 ^ state->v2 ^ state->v3; +} + +uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]) { + struct siphash state; + + assert(in); + assert(k); + + siphash24_init(&state, k); + siphash24_compress(in, inlen, &state); + + return siphash24_finalize(&state); +} diff --git a/src/systemd/src/basic/siphash24.h b/src/systemd/src/basic/siphash24.h new file mode 100644 index 00000000..0cc0163d --- /dev/null +++ b/src/systemd/src/basic/siphash24.h @@ -0,0 +1,23 @@ +#pragma once + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +struct siphash { + uint64_t v0; + uint64_t v1; + uint64_t v2; + uint64_t v3; + uint64_t padding; + size_t inlen; +}; + +void siphash24_init(struct siphash *state, const uint8_t k[16]); +void siphash24_compress(const void *in, size_t inlen, struct siphash *state); +uint64_t siphash24_finalize(struct siphash *state); + +uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]); diff --git a/src/systemd/src/basic/socket-util.h b/src/systemd/src/basic/socket-util.h new file mode 100644 index 00000000..d06a7645 --- /dev/null +++ b/src/systemd/src/basic/socket-util.h @@ -0,0 +1,141 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "macro.h" +#include "util.h" + +union sockaddr_union { + struct sockaddr sa; + struct sockaddr_in in; + struct sockaddr_in6 in6; + struct sockaddr_un un; + struct sockaddr_nl nl; + struct sockaddr_storage storage; + struct sockaddr_ll ll; +}; + +typedef struct SocketAddress { + union sockaddr_union sockaddr; + + /* We store the size here explicitly due to the weird + * sockaddr_un semantics for abstract sockets */ + socklen_t size; + + /* Socket type, i.e. SOCK_STREAM, SOCK_DGRAM, ... */ + int type; + + /* Socket protocol, IPPROTO_xxx, usually 0, except for netlink */ + int protocol; +} SocketAddress; + +typedef enum SocketAddressBindIPv6Only { + SOCKET_ADDRESS_DEFAULT, + SOCKET_ADDRESS_BOTH, + SOCKET_ADDRESS_IPV6_ONLY, + _SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX, + _SOCKET_ADDRESS_BIND_IPV6_ONLY_INVALID = -1 +} SocketAddressBindIPv6Only; + +#define socket_address_family(a) ((a)->sockaddr.sa.sa_family) + +int socket_address_parse(SocketAddress *a, const char *s); +int socket_address_parse_and_warn(SocketAddress *a, const char *s); +int socket_address_parse_netlink(SocketAddress *a, const char *s); +int socket_address_print(const SocketAddress *a, char **p); +int socket_address_verify(const SocketAddress *a) _pure_; +int socket_address_unlink(SocketAddress *a); + +bool socket_address_can_accept(const SocketAddress *a) _pure_; + +int socket_address_listen( + const SocketAddress *a, + int flags, + int backlog, + SocketAddressBindIPv6Only only, + const char *bind_to_device, + bool reuse_port, + bool free_bind, + bool transparent, + mode_t directory_mode, + mode_t socket_mode, + const char *label); +int make_socket_fd(int log_level, const char* address, int flags); + +bool socket_address_is(const SocketAddress *a, const char *s, int type); +bool socket_address_is_netlink(const SocketAddress *a, const char *s); + +bool socket_address_matches_fd(const SocketAddress *a, int fd); + +bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) _pure_; + +const char* socket_address_get_path(const SocketAddress *a); + +bool socket_ipv6_is_supported(void); + +int sockaddr_port(const struct sockaddr *_sa) _pure_; + +int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret); +int getpeername_pretty(int fd, char **ret); +int getsockname_pretty(int fd, char **ret); + +int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret); +int getnameinfo_pretty(int fd, char **ret); + +const char* socket_address_bind_ipv6_only_to_string(SocketAddressBindIPv6Only b) _const_; +SocketAddressBindIPv6Only socket_address_bind_ipv6_only_from_string(const char *s) _pure_; + +int netlink_family_to_string_alloc(int b, char **s); +int netlink_family_from_string(const char *s) _pure_; + +bool sockaddr_equal(const union sockaddr_union *a, const union sockaddr_union *b); + +int fd_inc_sndbuf(int fd, size_t n); +int fd_inc_rcvbuf(int fd, size_t n); + +int ip_tos_to_string_alloc(int i, char **s); +int ip_tos_from_string(const char *s); + +int getpeercred(int fd, struct ucred *ucred); +int getpeersec(int fd, char **ret); + +int send_one_fd_sa(int transport_fd, + int fd, + const struct sockaddr *sa, socklen_t len, + int flags); +#define send_one_fd(transport_fd, fd, flags) send_one_fd_sa(transport_fd, fd, NULL, 0, flags) +int receive_one_fd(int transport_fd, int flags); + +#define CMSG_FOREACH(cmsg, mh) \ + for ((cmsg) = CMSG_FIRSTHDR(mh); (cmsg); (cmsg) = CMSG_NXTHDR((mh), (cmsg))) diff --git a/src/systemd/src/basic/sparse-endian.h b/src/systemd/src/basic/sparse-endian.h new file mode 100644 index 00000000..02de0fec --- /dev/null +++ b/src/systemd/src/basic/sparse-endian.h @@ -0,0 +1,90 @@ +/* Copyright (c) 2012 Josh Triplett + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#ifndef SPARSE_ENDIAN_H +#define SPARSE_ENDIAN_H + +#include "nm-sd-adapt.h" + +#include +#include +#include + +#ifdef __CHECKER__ +#define __bitwise __attribute__((bitwise)) +#define __force __attribute__((force)) +#else +#define __bitwise +#define __force +#endif + +typedef uint16_t __bitwise le16_t; +typedef uint16_t __bitwise be16_t; +typedef uint32_t __bitwise le32_t; +typedef uint32_t __bitwise be32_t; +typedef uint64_t __bitwise le64_t; +typedef uint64_t __bitwise be64_t; + +#undef htobe16 +#undef htole16 +#undef be16toh +#undef le16toh +#undef htobe32 +#undef htole32 +#undef be32toh +#undef le32toh +#undef htobe64 +#undef htole64 +#undef be64toh +#undef le64toh + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define bswap_16_on_le(x) __bswap_16(x) +#define bswap_32_on_le(x) __bswap_32(x) +#define bswap_64_on_le(x) __bswap_64(x) +#define bswap_16_on_be(x) (x) +#define bswap_32_on_be(x) (x) +#define bswap_64_on_be(x) (x) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define bswap_16_on_le(x) (x) +#define bswap_32_on_le(x) (x) +#define bswap_64_on_le(x) (x) +#define bswap_16_on_be(x) __bswap_16(x) +#define bswap_32_on_be(x) __bswap_32(x) +#define bswap_64_on_be(x) __bswap_64(x) +#endif + +static inline le16_t htole16(uint16_t value) { return (le16_t __force) bswap_16_on_be(value); } +static inline le32_t htole32(uint32_t value) { return (le32_t __force) bswap_32_on_be(value); } +static inline le64_t htole64(uint64_t value) { return (le64_t __force) bswap_64_on_be(value); } + +static inline be16_t htobe16(uint16_t value) { return (be16_t __force) bswap_16_on_le(value); } +static inline be32_t htobe32(uint32_t value) { return (be32_t __force) bswap_32_on_le(value); } +static inline be64_t htobe64(uint64_t value) { return (be64_t __force) bswap_64_on_le(value); } + +static inline uint16_t le16toh(le16_t value) { return bswap_16_on_be((uint16_t __force)value); } +static inline uint32_t le32toh(le32_t value) { return bswap_32_on_be((uint32_t __force)value); } +static inline uint64_t le64toh(le64_t value) { return bswap_64_on_be((uint64_t __force)value); } + +static inline uint16_t be16toh(be16_t value) { return bswap_16_on_le((uint16_t __force)value); } +static inline uint32_t be32toh(be32_t value) { return bswap_32_on_le((uint32_t __force)value); } +static inline uint64_t be64toh(be64_t value) { return bswap_64_on_le((uint64_t __force)value); } + +#endif /* SPARSE_ENDIAN_H */ diff --git a/src/systemd/src/basic/string-table.c b/src/systemd/src/basic/string-table.c new file mode 100644 index 00000000..be02c2f9 --- /dev/null +++ b/src/systemd/src/basic/string-table.c @@ -0,0 +1,38 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include "string-table.h" +#include "string-util.h" + +ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) { + size_t i; + + if (!key) + return -1; + + for (i = 0; i < len; ++i) + if (streq_ptr(table[i], key)) + return (ssize_t) i; + + return -1; +} diff --git a/src/systemd/src/basic/string-table.h b/src/systemd/src/basic/string-table.h new file mode 100644 index 00000000..ee64d34f --- /dev/null +++ b/src/systemd/src/basic/string-table.h @@ -0,0 +1,91 @@ + +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include + +#include "macro.h" +#include "parse-util.h" +#include "string-util.h" + +ssize_t string_table_lookup(const char * const *table, size_t len, const char *key); + +/* For basic lookup tables with strictly enumerated entries */ +#define _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ + scope const char *name##_to_string(type i) { \ + if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \ + return NULL; \ + return name##_table[i]; \ + } + +#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ + scope type name##_from_string(const char *s) { \ + return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ + } + +#define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ + struct __useless_struct_to_allow_trailing_semicolon__ + +#define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) + +/* For string conversions where numbers are also acceptable */ +#define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ + int name##_to_string_alloc(type i, char **str) { \ + char *s; \ + if (i < 0 || i > max) \ + return -ERANGE; \ + if (i < (type) ELEMENTSOF(name##_table)) { \ + s = strdup(name##_table[i]); \ + if (!s) \ + return -ENOMEM; \ + } else { \ + if (asprintf(&s, "%i", i) < 0) \ + return -ENOMEM; \ + } \ + *str = s; \ + return 0; \ + } \ + type name##_from_string(const char *s) { \ + type i; \ + unsigned u = 0; \ + if (!s) \ + return (type) -1; \ + for (i = 0; i < (type) ELEMENTSOF(name##_table); i++) \ + if (streq_ptr(name##_table[i], s)) \ + return i; \ + if (safe_atou(s, &u) >= 0 && u <= max) \ + return (type) u; \ + return (type) -1; \ + } \ + struct __useless_struct_to_allow_trailing_semicolon__ diff --git a/src/systemd/src/basic/string-util.c b/src/systemd/src/basic/string-util.c new file mode 100644 index 00000000..35e00af9 --- /dev/null +++ b/src/systemd/src/basic/string-util.c @@ -0,0 +1,813 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include + +#include "alloc-util.h" +#if 0 /* NM_IGNORED */ +#include "gunicode.h" +#endif /* NM_IGNORED */ +#include "macro.h" +#include "string-util.h" +#include "utf8.h" +#include "util.h" + +int strcmp_ptr(const char *a, const char *b) { + + /* Like strcmp(), but tries to make sense of NULL pointers */ + if (a && b) + return strcmp(a, b); + + if (!a && b) + return -1; + + if (a && !b) + return 1; + + return 0; +} + +char* endswith(const char *s, const char *postfix) { + size_t sl, pl; + + assert(s); + assert(postfix); + + sl = strlen(s); + pl = strlen(postfix); + + if (pl == 0) + return (char*) s + sl; + + if (sl < pl) + return NULL; + + if (memcmp(s + sl - pl, postfix, pl) != 0) + return NULL; + + return (char*) s + sl - pl; +} + +char* endswith_no_case(const char *s, const char *postfix) { + size_t sl, pl; + + assert(s); + assert(postfix); + + sl = strlen(s); + pl = strlen(postfix); + + if (pl == 0) + return (char*) s + sl; + + if (sl < pl) + return NULL; + + if (strcasecmp(s + sl - pl, postfix) != 0) + return NULL; + + return (char*) s + sl - pl; +} + +char* first_word(const char *s, const char *word) { + size_t sl, wl; + const char *p; + + assert(s); + assert(word); + + /* Checks if the string starts with the specified word, either + * followed by NUL or by whitespace. Returns a pointer to the + * NUL or the first character after the whitespace. */ + + sl = strlen(s); + wl = strlen(word); + + if (sl < wl) + return NULL; + + if (wl == 0) + return (char*) s; + + if (memcmp(s, word, wl) != 0) + return NULL; + + p = s + wl; + if (*p == 0) + return (char*) p; + + if (!strchr(WHITESPACE, *p)) + return NULL; + + p += strspn(p, WHITESPACE); + return (char*) p; +} + +static size_t strcspn_escaped(const char *s, const char *reject) { + bool escaped = false; + int n; + + for (n=0; s[n]; n++) { + if (escaped) + escaped = false; + else if (s[n] == '\\') + escaped = true; + else if (strchr(reject, s[n])) + break; + } + + /* if s ends in \, return index of previous char */ + return n - escaped; +} + +/* Split a string into words. */ +const char* split(const char **state, size_t *l, const char *separator, bool quoted) { + const char *current; + + current = *state; + + if (!*current) { + assert(**state == '\0'); + return NULL; + } + + current += strspn(current, separator); + if (!*current) { + *state = current; + return NULL; + } + + if (quoted && strchr("\'\"", *current)) { + char quotechars[2] = {*current, '\0'}; + + *l = strcspn_escaped(current + 1, quotechars); + if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] || + (current[*l + 2] && !strchr(separator, current[*l + 2]))) { + /* right quote missing or garbage at the end */ + *state = current; + return NULL; + } + *state = current++ + *l + 2; + } else if (quoted) { + *l = strcspn_escaped(current, separator); + if (current[*l] && !strchr(separator, current[*l])) { + /* unfinished escape */ + *state = current; + return NULL; + } + *state = current + *l; + } else { + *l = strcspn(current, separator); + *state = current + *l; + } + + return current; +} + +char *strnappend(const char *s, const char *suffix, size_t b) { + size_t a; + char *r; + + if (!s && !suffix) + return strdup(""); + + if (!s) + return strndup(suffix, b); + + if (!suffix) + return strdup(s); + + assert(s); + assert(suffix); + + a = strlen(s); + if (b > ((size_t) -1) - a) + return NULL; + + r = new(char, a+b+1); + if (!r) + return NULL; + + memcpy(r, s, a); + memcpy(r+a, suffix, b); + r[a+b] = 0; + + return r; +} + +char *strappend(const char *s, const char *suffix) { + return strnappend(s, suffix, suffix ? strlen(suffix) : 0); +} + +char *strjoin(const char *x, ...) { + va_list ap; + size_t l; + char *r, *p; + + va_start(ap, x); + + if (x) { + l = strlen(x); + + for (;;) { + const char *t; + size_t n; + + t = va_arg(ap, const char *); + if (!t) + break; + + n = strlen(t); + if (n > ((size_t) -1) - l) { + va_end(ap); + return NULL; + } + + l += n; + } + } else + l = 0; + + va_end(ap); + + r = new(char, l+1); + if (!r) + return NULL; + + if (x) { + p = stpcpy(r, x); + + va_start(ap, x); + + for (;;) { + const char *t; + + t = va_arg(ap, const char *); + if (!t) + break; + + p = stpcpy(p, t); + } + + va_end(ap); + } else + r[0] = 0; + + return r; +} + +char *strstrip(char *s) { + char *e; + + /* Drops trailing whitespace. Modifies the string in + * place. Returns pointer to first non-space character */ + + s += strspn(s, WHITESPACE); + + for (e = strchr(s, 0); e > s; e --) + if (!strchr(WHITESPACE, e[-1])) + break; + + *e = 0; + + return s; +} + +char *delete_chars(char *s, const char *bad) { + char *f, *t; + + /* Drops all whitespace, regardless where in the string */ + + for (f = s, t = s; *f; f++) { + if (strchr(bad, *f)) + continue; + + *(t++) = *f; + } + + *t = 0; + + return s; +} + +char *truncate_nl(char *s) { + assert(s); + + s[strcspn(s, NEWLINE)] = 0; + return s; +} + +char *ascii_strlower(char *t) { + char *p; + + assert(t); + + for (p = t; *p; p++) + if (*p >= 'A' && *p <= 'Z') + *p = *p - 'A' + 'a'; + + return t; +} + +bool chars_intersect(const char *a, const char *b) { + const char *p; + + /* Returns true if any of the chars in a are in b. */ + for (p = a; *p; p++) + if (strchr(b, *p)) + return true; + + return false; +} + +bool string_has_cc(const char *p, const char *ok) { + const char *t; + + assert(p); + + /* + * Check if a string contains control characters. If 'ok' is + * non-NULL it may be a string containing additional CCs to be + * considered OK. + */ + + for (t = p; *t; t++) { + if (ok && strchr(ok, *t)) + continue; + + if (*t > 0 && *t < ' ') + return true; + + if (*t == 127) + return true; + } + + return false; +} + +#if 0 /* NM_IGNORED */ +static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { + size_t x; + char *r; + + assert(s); + assert(percent <= 100); + assert(new_length >= 3); + + if (old_length <= 3 || old_length <= new_length) + return strndup(s, old_length); + + r = new0(char, new_length+1); + if (!r) + return NULL; + + x = (new_length * percent) / 100; + + if (x > new_length - 3) + x = new_length - 3; + + memcpy(r, s, x); + r[x] = '.'; + r[x+1] = '.'; + r[x+2] = '.'; + memcpy(r + x + 3, + s + old_length - (new_length - x - 3), + new_length - x - 3); + + return r; +} + +char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) { + size_t x; + char *e; + const char *i, *j; + unsigned k, len, len2; + + assert(s); + assert(percent <= 100); + assert(new_length >= 3); + + /* if no multibyte characters use ascii_ellipsize_mem for speed */ + if (ascii_is_valid(s)) + return ascii_ellipsize_mem(s, old_length, new_length, percent); + + if (old_length <= 3 || old_length <= new_length) + return strndup(s, old_length); + + x = (new_length * percent) / 100; + + if (x > new_length - 3) + x = new_length - 3; + + k = 0; + for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) { + int c; + + c = utf8_encoded_to_unichar(i); + if (c < 0) + return NULL; + k += unichar_iswide(c) ? 2 : 1; + } + + if (k > x) /* last character was wide and went over quota */ + x ++; + + for (j = s + old_length; k < new_length && j > i; ) { + int c; + + j = utf8_prev_char(j); + c = utf8_encoded_to_unichar(j); + if (c < 0) + return NULL; + k += unichar_iswide(c) ? 2 : 1; + } + assert(i <= j); + + /* we don't actually need to ellipsize */ + if (i == j) + return memdup(s, old_length + 1); + + /* make space for ellipsis */ + j = utf8_next_char(j); + + len = i - s; + len2 = s + old_length - j; + e = new(char, len + 3 + len2 + 1); + if (!e) + return NULL; + + /* + printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n", + old_length, new_length, x, len, len2, k); + */ + + memcpy(e, s, len); + e[len] = 0xe2; /* tri-dot ellipsis: … */ + e[len + 1] = 0x80; + e[len + 2] = 0xa6; + + memcpy(e + len + 3, j, len2 + 1); + + return e; +} + +char *ellipsize(const char *s, size_t length, unsigned percent) { + return ellipsize_mem(s, strlen(s), length, percent); +} +#endif /* NM_IGNORED */ + +bool nulstr_contains(const char*nulstr, const char *needle) { + const char *i; + + if (!nulstr) + return false; + + NULSTR_FOREACH(i, nulstr) + if (streq(i, needle)) + return true; + + return false; +} + +char* strshorten(char *s, size_t l) { + assert(s); + + if (l < strlen(s)) + s[l] = 0; + + return s; +} + +char *strreplace(const char *text, const char *old_string, const char *new_string) { + const char *f; + char *t, *r; + size_t l, old_len, new_len; + + assert(text); + assert(old_string); + assert(new_string); + + old_len = strlen(old_string); + new_len = strlen(new_string); + + l = strlen(text); + r = new(char, l+1); + if (!r) + return NULL; + + f = text; + t = r; + while (*f) { + char *a; + size_t d, nl; + + if (!startswith(f, old_string)) { + *(t++) = *(f++); + continue; + } + + d = t - r; + nl = l - old_len + new_len; + a = realloc(r, nl + 1); + if (!a) + goto oom; + + l = nl; + r = a; + t = r + d; + + t = stpcpy(t, new_string); + f += old_len; + } + + *t = 0; + return r; + +oom: + free(r); + return NULL; +} + +char *strip_tab_ansi(char **ibuf, size_t *_isz) { + const char *i, *begin = NULL; + enum { + STATE_OTHER, + STATE_ESCAPE, + STATE_BRACKET + } state = STATE_OTHER; + char *obuf = NULL; + size_t osz = 0, isz; + FILE *f; + + assert(ibuf); + assert(*ibuf); + + /* Strips ANSI color and replaces TABs by 8 spaces */ + + isz = _isz ? *_isz : strlen(*ibuf); + + f = open_memstream(&obuf, &osz); + if (!f) + return NULL; + + for (i = *ibuf; i < *ibuf + isz + 1; i++) { + + switch (state) { + + case STATE_OTHER: + if (i >= *ibuf + isz) /* EOT */ + break; + else if (*i == '\x1B') + state = STATE_ESCAPE; + else if (*i == '\t') + fputs(" ", f); + else + fputc(*i, f); + break; + + case STATE_ESCAPE: + if (i >= *ibuf + isz) { /* EOT */ + fputc('\x1B', f); + break; + } else if (*i == '[') { + state = STATE_BRACKET; + begin = i + 1; + } else { + fputc('\x1B', f); + fputc(*i, f); + state = STATE_OTHER; + } + + break; + + case STATE_BRACKET: + + if (i >= *ibuf + isz || /* EOT */ + (!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) { + fputc('\x1B', f); + fputc('[', f); + state = STATE_OTHER; + i = begin-1; + } else if (*i == 'm') + state = STATE_OTHER; + break; + } + } + + if (ferror(f)) { + fclose(f); + free(obuf); + return NULL; + } + + fclose(f); + + free(*ibuf); + *ibuf = obuf; + + if (_isz) + *_isz = osz; + + return obuf; +} + +char *strextend(char **x, ...) { + va_list ap; + size_t f, l; + char *r, *p; + + assert(x); + + l = f = *x ? strlen(*x) : 0; + + va_start(ap, x); + for (;;) { + const char *t; + size_t n; + + t = va_arg(ap, const char *); + if (!t) + break; + + n = strlen(t); + if (n > ((size_t) -1) - l) { + va_end(ap); + return NULL; + } + + l += n; + } + va_end(ap); + + r = realloc(*x, l+1); + if (!r) + return NULL; + + p = r + f; + + va_start(ap, x); + for (;;) { + const char *t; + + t = va_arg(ap, const char *); + if (!t) + break; + + p = stpcpy(p, t); + } + va_end(ap); + + *p = 0; + *x = r; + + return r + l; +} + +char *strrep(const char *s, unsigned n) { + size_t l; + char *r, *p; + unsigned i; + + assert(s); + + l = strlen(s); + p = r = malloc(l * n + 1); + if (!r) + return NULL; + + for (i = 0; i < n; i++) + p = stpcpy(p, s); + + *p = 0; + return r; +} + +int split_pair(const char *s, const char *sep, char **l, char **r) { + char *x, *a, *b; + + assert(s); + assert(sep); + assert(l); + assert(r); + + if (isempty(sep)) + return -EINVAL; + + x = strstr(s, sep); + if (!x) + return -EINVAL; + + a = strndup(s, x - s); + if (!a) + return -ENOMEM; + + b = strdup(x + strlen(sep)); + if (!b) { + free(a); + return -ENOMEM; + } + + *l = a; + *r = b; + + return 0; +} + +int free_and_strdup(char **p, const char *s) { + char *t; + + assert(p); + + /* Replaces a string pointer with an strdup()ed new string, + * possibly freeing the old one. */ + + if (streq_ptr(*p, s)) + return 0; + + if (s) { + t = strdup(s); + if (!t) + return -ENOMEM; + } else + t = NULL; + + free(*p); + *p = t; + + return 1; +} + +#pragma GCC push_options +#pragma GCC optimize("O0") + +void* memory_erase(void *p, size_t l) { + volatile uint8_t* x = (volatile uint8_t*) p; + + /* This basically does what memset() does, but hopefully isn't + * optimized away by the compiler. One of those days, when + * glibc learns memset_s() we should replace this call by + * memset_s(), but until then this has to do. */ + + for (; l > 0; l--) + *(x++) = 'x'; + + return p; +} + +#pragma GCC pop_options + +char* string_erase(char *x) { + + if (!x) + return NULL; + + /* A delicious drop of snake-oil! To be called on memory where + * we stored passphrases or so, after we used them. */ + + return memory_erase(x, strlen(x)); +} + +char *string_free_erase(char *s) { + return mfree(string_erase(s)); +} + +bool string_is_safe(const char *p) { + const char *t; + + if (!p) + return false; + + for (t = p; *t; t++) { + if (*t > 0 && *t < ' ') /* no control characters */ + return false; + + if (strchr(QUOTES "\\\x7f", *t)) + return false; + } + + return true; +} diff --git a/src/systemd/src/basic/string-util.h b/src/systemd/src/basic/string-util.h new file mode 100644 index 00000000..f6aa4584 --- /dev/null +++ b/src/systemd/src/basic/string-util.h @@ -0,0 +1,188 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "macro.h" + +/* What is interpreted as whitespace? */ +#define WHITESPACE " \t\n\r" +#define NEWLINE "\n\r" +#define QUOTES "\"\'" +#define COMMENTS "#;" +#define GLOB_CHARS "*?[" +#define DIGITS "0123456789" +#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" +#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS +#define ALPHANUMERICAL LETTERS DIGITS + +#define streq(a,b) (strcmp((a),(b)) == 0) +#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) +#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) +#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) + +int strcmp_ptr(const char *a, const char *b) _pure_; + +static inline bool streq_ptr(const char *a, const char *b) { + return strcmp_ptr(a, b) == 0; +} + +static inline const char* strempty(const char *s) { + return s ? s : ""; +} + +static inline const char* strnull(const char *s) { + return s ? s : "(null)"; +} + +static inline const char *strna(const char *s) { + return s ? s : "n/a"; +} + +static inline bool isempty(const char *p) { + return !p || !p[0]; +} + +static inline char *startswith(const char *s, const char *prefix) { + size_t l; + + l = strlen(prefix); + if (strncmp(s, prefix, l) == 0) + return (char*) s + l; + + return NULL; +} + +static inline char *startswith_no_case(const char *s, const char *prefix) { + size_t l; + + l = strlen(prefix); + if (strncasecmp(s, prefix, l) == 0) + return (char*) s + l; + + return NULL; +} + +char *endswith(const char *s, const char *postfix) _pure_; +char *endswith_no_case(const char *s, const char *postfix) _pure_; + +char *first_word(const char *s, const char *word) _pure_; + +const char* split(const char **state, size_t *l, const char *separator, bool quoted); + +#define FOREACH_WORD(word, length, s, state) \ + _FOREACH_WORD(word, length, s, WHITESPACE, false, state) + +#define FOREACH_WORD_SEPARATOR(word, length, s, separator, state) \ + _FOREACH_WORD(word, length, s, separator, false, state) + +#define FOREACH_WORD_QUOTED(word, length, s, state) \ + _FOREACH_WORD(word, length, s, WHITESPACE, true, state) + +#define _FOREACH_WORD(word, length, s, separator, quoted, state) \ + for ((state) = (s), (word) = split(&(state), &(length), (separator), (quoted)); (word); (word) = split(&(state), &(length), (separator), (quoted))) + +char *strappend(const char *s, const char *suffix); +char *strnappend(const char *s, const char *suffix, size_t length); + +char *strjoin(const char *x, ...) _sentinel_; + +#define strjoina(a, ...) \ + ({ \ + const char *_appendees_[] = { a, __VA_ARGS__ }; \ + char *_d_, *_p_; \ + int _len_ = 0; \ + unsigned _i_; \ + for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ + _len_ += strlen(_appendees_[_i_]); \ + _p_ = _d_ = alloca(_len_ + 1); \ + for (_i_ = 0; _i_ < ELEMENTSOF(_appendees_) && _appendees_[_i_]; _i_++) \ + _p_ = stpcpy(_p_, _appendees_[_i_]); \ + *_p_ = 0; \ + _d_; \ + }) + +char *strstrip(char *s); +char *delete_chars(char *s, const char *bad); +char *truncate_nl(char *s); + +char *ascii_strlower(char *path); + +bool chars_intersect(const char *a, const char *b) _pure_; + +static inline bool _pure_ in_charset(const char *s, const char* charset) { + assert(s); + assert(charset); + return s[strspn(s, charset)] == '\0'; +} + +bool string_has_cc(const char *p, const char *ok) _pure_; + +char *ellipsize_mem(const char *s, size_t old_length_bytes, size_t new_length_columns, unsigned percent); +char *ellipsize(const char *s, size_t length, unsigned percent); + +bool nulstr_contains(const char*nulstr, const char *needle); + +char* strshorten(char *s, size_t l); + +char *strreplace(const char *text, const char *old_string, const char *new_string); + +char *strip_tab_ansi(char **p, size_t *l); + +char *strextend(char **x, ...) _sentinel_; + +char *strrep(const char *s, unsigned n); + +int split_pair(const char *s, const char *sep, char **l, char **r); + +int free_and_strdup(char **p, const char *s); + +/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */ +static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) { + + if (needlelen <= 0) + return (void*) haystack; + + if (haystacklen < needlelen) + return NULL; + + assert(haystack); + assert(needle); + + return memmem(haystack, haystacklen, needle, needlelen); +} + +void* memory_erase(void *p, size_t l); +char *string_erase(char *x); + +char *string_free_erase(char *s); +DEFINE_TRIVIAL_CLEANUP_FUNC(char *, string_free_erase); +#define _cleanup_string_free_erase_ _cleanup_(string_free_erasep) + +bool string_is_safe(const char *p) _pure_; diff --git a/src/systemd/src/basic/strv.c b/src/systemd/src/basic/strv.c new file mode 100644 index 00000000..38624902 --- /dev/null +++ b/src/systemd/src/basic/strv.c @@ -0,0 +1,879 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include + +#include "alloc-util.h" +#include "escape.h" +#if 0 /* NM_IGNORED */ +#include "extract-word.h" +#endif /* NM_IGNORED */ +#include "string-util.h" +#include "strv.h" +#include "util.h" + +char *strv_find(char **l, const char *name) { + char **i; + + assert(name); + + STRV_FOREACH(i, l) + if (streq(*i, name)) + return *i; + + return NULL; +} + +char *strv_find_prefix(char **l, const char *name) { + char **i; + + assert(name); + + STRV_FOREACH(i, l) + if (startswith(*i, name)) + return *i; + + return NULL; +} + +char *strv_find_startswith(char **l, const char *name) { + char **i, *e; + + assert(name); + + /* Like strv_find_prefix, but actually returns only the + * suffix, not the whole item */ + + STRV_FOREACH(i, l) { + e = startswith(*i, name); + if (e) + return e; + } + + return NULL; +} + +void strv_clear(char **l) { + char **k; + + if (!l) + return; + + for (k = l; *k; k++) + free(*k); + + *l = NULL; +} + +char **strv_free(char **l) { + strv_clear(l); + free(l); + return NULL; +} + +char **strv_free_erase(char **l) { + char **i; + + STRV_FOREACH(i, l) + string_erase(*i); + + return strv_free(l); +} + +char **strv_copy(char * const *l) { + char **r, **k; + + k = r = new(char*, strv_length(l) + 1); + if (!r) + return NULL; + + if (l) + for (; *l; k++, l++) { + *k = strdup(*l); + if (!*k) { + strv_free(r); + return NULL; + } + } + + *k = NULL; + return r; +} + +unsigned strv_length(char * const *l) { + unsigned n = 0; + + if (!l) + return 0; + + for (; *l; l++) + n++; + + return n; +} + +char **strv_new_ap(const char *x, va_list ap) { + const char *s; + char **a; + unsigned n = 0, i = 0; + va_list aq; + + /* As a special trick we ignore all listed strings that equal + * (const char*) -1. This is supposed to be used with the + * STRV_IFNOTNULL() macro to include possibly NULL strings in + * the string list. */ + + if (x) { + n = x == (const char*) -1 ? 0 : 1; + + va_copy(aq, ap); + while ((s = va_arg(aq, const char*))) { + if (s == (const char*) -1) + continue; + + n++; + } + + va_end(aq); + } + + a = new(char*, n+1); + if (!a) + return NULL; + + if (x) { + if (x != (const char*) -1) { + a[i] = strdup(x); + if (!a[i]) + goto fail; + i++; + } + + while ((s = va_arg(ap, const char*))) { + + if (s == (const char*) -1) + continue; + + a[i] = strdup(s); + if (!a[i]) + goto fail; + + i++; + } + } + + a[i] = NULL; + + return a; + +fail: + strv_free(a); + return NULL; +} + +char **strv_new(const char *x, ...) { + char **r; + va_list ap; + + va_start(ap, x); + r = strv_new_ap(x, ap); + va_end(ap); + + return r; +} + +int strv_extend_strv(char ***a, char **b, bool filter_duplicates) { + char **s, **t; + size_t p, q, i = 0, j; + + assert(a); + + if (strv_isempty(b)) + return 0; + + p = strv_length(*a); + q = strv_length(b); + + t = realloc(*a, sizeof(char*) * (p + q + 1)); + if (!t) + return -ENOMEM; + + t[p] = NULL; + *a = t; + + STRV_FOREACH(s, b) { + + if (filter_duplicates && strv_contains(t, *s)) + continue; + + t[p+i] = strdup(*s); + if (!t[p+i]) + goto rollback; + + i++; + t[p+i] = NULL; + } + + assert(i <= q); + + return (int) i; + +rollback: + for (j = 0; j < i; j++) + free(t[p + j]); + + t[p] = NULL; + return -ENOMEM; +} + +int strv_extend_strv_concat(char ***a, char **b, const char *suffix) { + int r; + char **s; + + STRV_FOREACH(s, b) { + char *v; + + v = strappend(*s, suffix); + if (!v) + return -ENOMEM; + + r = strv_push(a, v); + if (r < 0) { + free(v); + return r; + } + } + + return 0; +} + +char **strv_split(const char *s, const char *separator) { + const char *word, *state; + size_t l; + unsigned n, i; + char **r; + + assert(s); + + n = 0; + FOREACH_WORD_SEPARATOR(word, l, s, separator, state) + n++; + + r = new(char*, n+1); + if (!r) + return NULL; + + i = 0; + FOREACH_WORD_SEPARATOR(word, l, s, separator, state) { + r[i] = strndup(word, l); + if (!r[i]) { + strv_free(r); + return NULL; + } + + i++; + } + + r[i] = NULL; + return r; +} + +char **strv_split_newlines(const char *s) { + char **l; + unsigned n; + + assert(s); + + /* Special version of strv_split() that splits on newlines and + * suppresses an empty string at the end */ + + l = strv_split(s, NEWLINE); + if (!l) + return NULL; + + n = strv_length(l); + if (n <= 0) + return l; + + if (isempty(l[n - 1])) + l[n - 1] = mfree(l[n - 1]); + + return l; +} + +#if 0 /* NM_IGNORED */ +int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags) { + _cleanup_strv_free_ char **l = NULL; + size_t n = 0, allocated = 0; + int r; + + assert(t); + assert(s); + + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&s, &word, separators, flags); + if (r < 0) + return r; + if (r == 0) + break; + + if (!GREEDY_REALLOC(l, allocated, n + 2)) + return -ENOMEM; + + l[n++] = word; + word = NULL; + + l[n] = NULL; + } + + if (!l) { + l = new0(char*, 1); + if (!l) + return -ENOMEM; + } + + *t = l; + l = NULL; + + return (int) n; +} +#endif /* NM_IGNORED */ + +char *strv_join(char **l, const char *separator) { + char *r, *e; + char **s; + size_t n, k; + + if (!separator) + separator = " "; + + k = strlen(separator); + + n = 0; + STRV_FOREACH(s, l) { + if (n != 0) + n += k; + n += strlen(*s); + } + + r = new(char, n+1); + if (!r) + return NULL; + + e = r; + STRV_FOREACH(s, l) { + if (e != r) + e = stpcpy(e, separator); + + e = stpcpy(e, *s); + } + + *e = 0; + + return r; +} + +char *strv_join_quoted(char **l) { + char *buf = NULL; + char **s; + size_t allocated = 0, len = 0; + + STRV_FOREACH(s, l) { + /* assuming here that escaped string cannot be more + * than twice as long, and reserving space for the + * separator and quotes. + */ + _cleanup_free_ char *esc = NULL; + size_t needed; + + if (!GREEDY_REALLOC(buf, allocated, + len + strlen(*s) * 2 + 3)) + goto oom; + + esc = cescape(*s); + if (!esc) + goto oom; + + needed = snprintf(buf + len, allocated - len, "%s\"%s\"", + len > 0 ? " " : "", esc); + assert(needed < allocated - len); + len += needed; + } + + if (!buf) + buf = malloc0(1); + + return buf; + + oom: + free(buf); + return NULL; +} + +int strv_push(char ***l, char *value) { + char **c; + unsigned n, m; + + if (!value) + return 0; + + n = strv_length(*l); + + /* Increase and check for overflow */ + m = n + 2; + if (m < n) + return -ENOMEM; + + c = realloc_multiply(*l, sizeof(char*), m); + if (!c) + return -ENOMEM; + + c[n] = value; + c[n+1] = NULL; + + *l = c; + return 0; +} + +int strv_push_pair(char ***l, char *a, char *b) { + char **c; + unsigned n, m; + + if (!a && !b) + return 0; + + n = strv_length(*l); + + /* increase and check for overflow */ + m = n + !!a + !!b + 1; + if (m < n) + return -ENOMEM; + + c = realloc_multiply(*l, sizeof(char*), m); + if (!c) + return -ENOMEM; + + if (a) + c[n++] = a; + if (b) + c[n++] = b; + c[n] = NULL; + + *l = c; + return 0; +} + +int strv_push_prepend(char ***l, char *value) { + char **c; + unsigned n, m, i; + + if (!value) + return 0; + + n = strv_length(*l); + + /* increase and check for overflow */ + m = n + 2; + if (m < n) + return -ENOMEM; + + c = new(char*, m); + if (!c) + return -ENOMEM; + + for (i = 0; i < n; i++) + c[i+1] = (*l)[i]; + + c[0] = value; + c[n+1] = NULL; + + free(*l); + *l = c; + + return 0; +} + +int strv_consume(char ***l, char *value) { + int r; + + r = strv_push(l, value); + if (r < 0) + free(value); + + return r; +} + +int strv_consume_pair(char ***l, char *a, char *b) { + int r; + + r = strv_push_pair(l, a, b); + if (r < 0) { + free(a); + free(b); + } + + return r; +} + +int strv_consume_prepend(char ***l, char *value) { + int r; + + r = strv_push_prepend(l, value); + if (r < 0) + free(value); + + return r; +} + +int strv_extend(char ***l, const char *value) { + char *v; + + if (!value) + return 0; + + v = strdup(value); + if (!v) + return -ENOMEM; + + return strv_consume(l, v); +} + +char **strv_uniq(char **l) { + char **i; + + /* Drops duplicate entries. The first identical string will be + * kept, the others dropped */ + + STRV_FOREACH(i, l) + strv_remove(i+1, *i); + + return l; +} + +bool strv_is_uniq(char **l) { + char **i; + + STRV_FOREACH(i, l) + if (strv_find(i+1, *i)) + return false; + + return true; +} + +char **strv_remove(char **l, const char *s) { + char **f, **t; + + if (!l) + return NULL; + + assert(s); + + /* Drops every occurrence of s in the string list, edits + * in-place. */ + + for (f = t = l; *f; f++) + if (streq(*f, s)) + free(*f); + else + *(t++) = *f; + + *t = NULL; + return l; +} + +char **strv_parse_nulstr(const char *s, size_t l) { + const char *p; + unsigned c = 0, i = 0; + char **v; + + assert(s || l <= 0); + + if (l <= 0) + return new0(char*, 1); + + for (p = s; p < s + l; p++) + if (*p == 0) + c++; + + if (s[l-1] != 0) + c++; + + v = new0(char*, c+1); + if (!v) + return NULL; + + p = s; + while (p < s + l) { + const char *e; + + e = memchr(p, 0, s + l - p); + + v[i] = strndup(p, e ? e - p : s + l - p); + if (!v[i]) { + strv_free(v); + return NULL; + } + + i++; + + if (!e) + break; + + p = e + 1; + } + + assert(i == c); + + return v; +} + +char **strv_split_nulstr(const char *s) { + const char *i; + char **r = NULL; + + NULSTR_FOREACH(i, s) + if (strv_extend(&r, i) < 0) { + strv_free(r); + return NULL; + } + + if (!r) + return strv_new(NULL, NULL); + + return r; +} + +int strv_make_nulstr(char **l, char **p, size_t *q) { + size_t n_allocated = 0, n = 0; + _cleanup_free_ char *m = NULL; + char **i; + + assert(p); + assert(q); + + STRV_FOREACH(i, l) { + size_t z; + + z = strlen(*i); + + if (!GREEDY_REALLOC(m, n_allocated, n + z + 1)) + return -ENOMEM; + + memcpy(m + n, *i, z + 1); + n += z + 1; + } + + if (!m) { + m = new0(char, 1); + if (!m) + return -ENOMEM; + n = 0; + } + + *p = m; + *q = n; + + m = NULL; + + return 0; +} + +bool strv_overlap(char **a, char **b) { + char **i; + + STRV_FOREACH(i, a) + if (strv_contains(b, *i)) + return true; + + return false; +} + +static int str_compare(const void *_a, const void *_b) { + const char **a = (const char**) _a, **b = (const char**) _b; + + return strcmp(*a, *b); +} + +char **strv_sort(char **l) { + + if (strv_isempty(l)) + return l; + + qsort(l, strv_length(l), sizeof(char*), str_compare); + return l; +} + +bool strv_equal(char **a, char **b) { + + if (strv_isempty(a)) + return strv_isempty(b); + + if (strv_isempty(b)) + return false; + + for ( ; *a || *b; ++a, ++b) + if (!streq_ptr(*a, *b)) + return false; + + return true; +} + +void strv_print(char **l) { + char **s; + + STRV_FOREACH(s, l) + puts(*s); +} + +int strv_extendf(char ***l, const char *format, ...) { + va_list ap; + char *x; + int r; + + va_start(ap, format); + r = vasprintf(&x, format, ap); + va_end(ap); + + if (r < 0) + return -ENOMEM; + + return strv_consume(l, x); +} + +char **strv_reverse(char **l) { + unsigned n, i; + + n = strv_length(l); + if (n <= 1) + return l; + + for (i = 0; i < n / 2; i++) { + char *t; + + t = l[i]; + l[i] = l[n-1-i]; + l[n-1-i] = t; + } + + return l; +} + +char **strv_shell_escape(char **l, const char *bad) { + char **s; + + /* Escapes every character in every string in l that is in bad, + * edits in-place, does not roll-back on error. */ + + STRV_FOREACH(s, l) { + char *v; + + v = shell_escape(*s, bad); + if (!v) + return NULL; + + free(*s); + *s = v; + } + + return l; +} + +bool strv_fnmatch(char* const* patterns, const char *s, int flags) { + char* const* p; + + STRV_FOREACH(p, patterns) + if (fnmatch(*p, s, 0) == 0) + return true; + + return false; +} + +char ***strv_free_free(char ***l) { + char ***i; + + if (!l) + return NULL; + + for (i = l; *i; i++) + strv_free(*i); + + free(l); + return NULL; +} + +char **strv_skip(char **l, size_t n) { + + while (n > 0) { + if (strv_isempty(l)) + return l; + + l++, n--; + } + + return l; +} + +int strv_extend_n(char ***l, const char *value, size_t n) { + size_t i, j, k; + char **nl; + + assert(l); + + if (!value) + return 0; + if (n == 0) + return 0; + + /* Adds the value value n times to l */ + + k = strv_length(*l); + + nl = realloc(*l, sizeof(char*) * (k + n + 1)); + if (!nl) + return -ENOMEM; + + *l = nl; + + for (i = k; i < k + n; i++) { + nl[i] = strdup(value); + if (!nl[i]) + goto rollback; + } + + nl[i] = NULL; + return 0; + +rollback: + for (j = k; j < i; j++) + free(nl[j]); + + nl[k] = NULL; + return -ENOMEM; +} diff --git a/src/systemd/src/basic/strv.h b/src/systemd/src/basic/strv.h new file mode 100644 index 00000000..d3608af3 --- /dev/null +++ b/src/systemd/src/basic/strv.h @@ -0,0 +1,177 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "alloc-util.h" +#if 0 /* NM_IGNORED */ +#include "extract-word.h" +#endif /* NM_IGNORED */ +#include "macro.h" +#include "util.h" + +char *strv_find(char **l, const char *name) _pure_; +char *strv_find_prefix(char **l, const char *name) _pure_; +char *strv_find_startswith(char **l, const char *name) _pure_; + +char **strv_free(char **l); +DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free); +#define _cleanup_strv_free_ _cleanup_(strv_freep) + +char **strv_free_erase(char **l); +DEFINE_TRIVIAL_CLEANUP_FUNC(char**, strv_free_erase); +#define _cleanup_strv_free_erase_ _cleanup_(strv_free_erasep) + +void strv_clear(char **l); + +char **strv_copy(char * const *l); +unsigned strv_length(char * const *l) _pure_; + +int strv_extend_strv(char ***a, char **b, bool filter_duplicates); +int strv_extend_strv_concat(char ***a, char **b, const char *suffix); +int strv_extend(char ***l, const char *value); +int strv_extendf(char ***l, const char *format, ...) _printf_(2,0); +int strv_push(char ***l, char *value); +int strv_push_pair(char ***l, char *a, char *b); +int strv_push_prepend(char ***l, char *value); +int strv_consume(char ***l, char *value); +int strv_consume_pair(char ***l, char *a, char *b); +int strv_consume_prepend(char ***l, char *value); + +char **strv_remove(char **l, const char *s); +char **strv_uniq(char **l); +bool strv_is_uniq(char **l); + +bool strv_equal(char **a, char **b); + +#define strv_contains(l, s) (!!strv_find((l), (s))) + +char **strv_new(const char *x, ...) _sentinel_; +char **strv_new_ap(const char *x, va_list ap); + +static inline const char* STRV_IFNOTNULL(const char *x) { + return x ? x : (const char *) -1; +} + +static inline bool strv_isempty(char * const *l) { + return !l || !*l; +} + +char **strv_split(const char *s, const char *separator); +char **strv_split_newlines(const char *s); + +#if 0 /* NM_IGNORED */ +int strv_split_extract(char ***t, const char *s, const char *separators, ExtractFlags flags); +#endif /* NM_IGNORED */ + +char *strv_join(char **l, const char *separator); +char *strv_join_quoted(char **l); + +char **strv_parse_nulstr(const char *s, size_t l); +char **strv_split_nulstr(const char *s); +int strv_make_nulstr(char **l, char **p, size_t *n); + +bool strv_overlap(char **a, char **b) _pure_; + +#define STRV_FOREACH(s, l) \ + for ((s) = (l); (s) && *(s); (s)++) + +#define STRV_FOREACH_BACKWARDS(s, l) \ + STRV_FOREACH(s, l) \ + ; \ + for ((s)--; (l) && ((s) >= (l)); (s)--) + +#define STRV_FOREACH_PAIR(x, y, l) \ + for ((x) = (l), (y) = (x+1); (x) && *(x) && *(y); (x) += 2, (y) = (x + 1)) + +char **strv_sort(char **l); +void strv_print(char **l); + +#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL })) + +#define STRV_MAKE_EMPTY ((char*[1]) { NULL }) + +#define strv_from_stdarg_alloca(first) \ + ({ \ + char **_l; \ + \ + if (!first) \ + _l = (char**) &first; \ + else { \ + unsigned _n; \ + va_list _ap; \ + \ + _n = 1; \ + va_start(_ap, first); \ + while (va_arg(_ap, char*)) \ + _n++; \ + va_end(_ap); \ + \ + _l = newa(char*, _n+1); \ + _l[_n = 0] = (char*) first; \ + va_start(_ap, first); \ + for (;;) { \ + _l[++_n] = va_arg(_ap, char*); \ + if (!_l[_n]) \ + break; \ + } \ + va_end(_ap); \ + } \ + _l; \ + }) + +#define STR_IN_SET(x, ...) strv_contains(STRV_MAKE(__VA_ARGS__), x) + +#define FOREACH_STRING(x, ...) \ + for (char **_l = ({ \ + char **_ll = STRV_MAKE(__VA_ARGS__); \ + x = _ll ? _ll[0] : NULL; \ + _ll; \ + }); \ + _l && *_l; \ + x = ({ \ + _l ++; \ + _l[0]; \ + })) + +char **strv_reverse(char **l); +char **strv_shell_escape(char **l, const char *bad); + +bool strv_fnmatch(char* const* patterns, const char *s, int flags); + +static inline bool strv_fnmatch_or_empty(char* const* patterns, const char *s, int flags) { + assert(s); + return strv_isempty(patterns) || + strv_fnmatch(patterns, s, flags); +} + +char ***strv_free_free(char ***l); + +char **strv_skip(char **l, size_t n); + +int strv_extend_n(char ***l, const char *value, size_t n); diff --git a/src/systemd/src/basic/time-util.c b/src/systemd/src/basic/time-util.c new file mode 100644 index 00000000..8ca41f0c --- /dev/null +++ b/src/systemd/src/basic/time-util.c @@ -0,0 +1,1154 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "log.h" +#include "macro.h" +#include "parse-util.h" +#include "path-util.h" +#include "string-util.h" +#include "strv.h" +#include "time-util.h" + +usec_t now(clockid_t clock_id) { + struct timespec ts; + + assert_se(clock_gettime(clock_id, &ts) == 0); + + return timespec_load(&ts); +} + +nsec_t now_nsec(clockid_t clock_id) { + struct timespec ts; + + assert_se(clock_gettime(clock_id, &ts) == 0); + + return timespec_load_nsec(&ts); +} + +dual_timestamp* dual_timestamp_get(dual_timestamp *ts) { + assert(ts); + + ts->realtime = now(CLOCK_REALTIME); + ts->monotonic = now(CLOCK_MONOTONIC); + + return ts; +} + +dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) { + int64_t delta; + assert(ts); + + if (u == USEC_INFINITY || u <= 0) { + ts->realtime = ts->monotonic = u; + return ts; + } + + ts->realtime = u; + + delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u; + ts->monotonic = now(CLOCK_MONOTONIC); + + if ((int64_t) ts->monotonic > delta) + ts->monotonic -= delta; + else + ts->monotonic = 0; + + return ts; +} + +dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) { + int64_t delta; + assert(ts); + + if (u == USEC_INFINITY) { + ts->realtime = ts->monotonic = USEC_INFINITY; + return ts; + } + + ts->monotonic = u; + delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u; + + ts->realtime = now(CLOCK_REALTIME); + if ((int64_t) ts->realtime > delta) + ts->realtime -= delta; + else + ts->realtime = 0; + + return ts; +} + +dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u) { + int64_t delta; + + if (u == USEC_INFINITY) { + ts->realtime = ts->monotonic = USEC_INFINITY; + return ts; + } + ts->realtime = now(CLOCK_REALTIME); + ts->monotonic = now(CLOCK_MONOTONIC); + + delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u; + + if ((int64_t) ts->realtime > delta) + ts->realtime -= delta; + else + ts->realtime = 0; + + if ((int64_t) ts->monotonic > delta) + ts->monotonic -= delta; + else + ts->monotonic = 0; + + return ts; +} + + +usec_t timespec_load(const struct timespec *ts) { + assert(ts); + + if (ts->tv_sec == (time_t) -1 && + ts->tv_nsec == (long) -1) + return USEC_INFINITY; + + if ((usec_t) ts->tv_sec > (UINT64_MAX - (ts->tv_nsec / NSEC_PER_USEC)) / USEC_PER_SEC) + return USEC_INFINITY; + + return + (usec_t) ts->tv_sec * USEC_PER_SEC + + (usec_t) ts->tv_nsec / NSEC_PER_USEC; +} + +nsec_t timespec_load_nsec(const struct timespec *ts) { + assert(ts); + + if (ts->tv_sec == (time_t) -1 && + ts->tv_nsec == (long) -1) + return NSEC_INFINITY; + + return + (nsec_t) ts->tv_sec * NSEC_PER_SEC + + (nsec_t) ts->tv_nsec; +} + +struct timespec *timespec_store(struct timespec *ts, usec_t u) { + assert(ts); + + if (u == USEC_INFINITY) { + ts->tv_sec = (time_t) -1; + ts->tv_nsec = (long) -1; + return ts; + } + + ts->tv_sec = (time_t) (u / USEC_PER_SEC); + ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC); + + return ts; +} + +#if 0 /* NM_IGNORED */ +usec_t timeval_load(const struct timeval *tv) { + assert(tv); + + if (tv->tv_sec == (time_t) -1 && + tv->tv_usec == (suseconds_t) -1) + return USEC_INFINITY; + + if ((usec_t) tv->tv_sec > (UINT64_MAX - tv->tv_usec) / USEC_PER_SEC) + return USEC_INFINITY; + + return + (usec_t) tv->tv_sec * USEC_PER_SEC + + (usec_t) tv->tv_usec; +} + +struct timeval *timeval_store(struct timeval *tv, usec_t u) { + assert(tv); + + if (u == USEC_INFINITY) { + tv->tv_sec = (time_t) -1; + tv->tv_usec = (suseconds_t) -1; + } else { + tv->tv_sec = (time_t) (u / USEC_PER_SEC); + tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC); + } + + return tv; +} + +static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) { + struct tm tm; + time_t sec; + + assert(buf); + assert(l > 0); + + if (t <= 0 || t == USEC_INFINITY) + return NULL; + + sec = (time_t) (t / USEC_PER_SEC); + localtime_or_gmtime_r(&sec, &tm, utc); + + if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0) + return NULL; + + return buf; +} + +char *format_timestamp(char *buf, size_t l, usec_t t) { + return format_timestamp_internal(buf, l, t, false); +} + +char *format_timestamp_utc(char *buf, size_t l, usec_t t) { + return format_timestamp_internal(buf, l, t, true); +} + +static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool utc) { + struct tm tm; + time_t sec; + + assert(buf); + assert(l > 0); + + if (t <= 0 || t == USEC_INFINITY) + return NULL; + + sec = (time_t) (t / USEC_PER_SEC); + localtime_or_gmtime_r(&sec, &tm, utc); + + if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0) + return NULL; + snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC)); + if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0) + return NULL; + + return buf; +} + +char *format_timestamp_us(char *buf, size_t l, usec_t t) { + return format_timestamp_internal_us(buf, l, t, false); +} + +char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) { + return format_timestamp_internal_us(buf, l, t, true); +} + +char *format_timestamp_relative(char *buf, size_t l, usec_t t) { + const char *s; + usec_t n, d; + + if (t <= 0 || t == USEC_INFINITY) + return NULL; + + n = now(CLOCK_REALTIME); + if (n > t) { + d = n - t; + s = "ago"; + } else { + d = t - n; + s = "left"; + } + + if (d >= USEC_PER_YEAR) + snprintf(buf, l, USEC_FMT " years " USEC_FMT " months %s", + d / USEC_PER_YEAR, + (d % USEC_PER_YEAR) / USEC_PER_MONTH, s); + else if (d >= USEC_PER_MONTH) + snprintf(buf, l, USEC_FMT " months " USEC_FMT " days %s", + d / USEC_PER_MONTH, + (d % USEC_PER_MONTH) / USEC_PER_DAY, s); + else if (d >= USEC_PER_WEEK) + snprintf(buf, l, USEC_FMT " weeks " USEC_FMT " days %s", + d / USEC_PER_WEEK, + (d % USEC_PER_WEEK) / USEC_PER_DAY, s); + else if (d >= 2*USEC_PER_DAY) + snprintf(buf, l, USEC_FMT " days %s", d / USEC_PER_DAY, s); + else if (d >= 25*USEC_PER_HOUR) + snprintf(buf, l, "1 day " USEC_FMT "h %s", + (d - USEC_PER_DAY) / USEC_PER_HOUR, s); + else if (d >= 6*USEC_PER_HOUR) + snprintf(buf, l, USEC_FMT "h %s", + d / USEC_PER_HOUR, s); + else if (d >= USEC_PER_HOUR) + snprintf(buf, l, USEC_FMT "h " USEC_FMT "min %s", + d / USEC_PER_HOUR, + (d % USEC_PER_HOUR) / USEC_PER_MINUTE, s); + else if (d >= 5*USEC_PER_MINUTE) + snprintf(buf, l, USEC_FMT "min %s", + d / USEC_PER_MINUTE, s); + else if (d >= USEC_PER_MINUTE) + snprintf(buf, l, USEC_FMT "min " USEC_FMT "s %s", + d / USEC_PER_MINUTE, + (d % USEC_PER_MINUTE) / USEC_PER_SEC, s); + else if (d >= USEC_PER_SEC) + snprintf(buf, l, USEC_FMT "s %s", + d / USEC_PER_SEC, s); + else if (d >= USEC_PER_MSEC) + snprintf(buf, l, USEC_FMT "ms %s", + d / USEC_PER_MSEC, s); + else if (d > 0) + snprintf(buf, l, USEC_FMT"us %s", + d, s); + else + snprintf(buf, l, "now"); + + buf[l-1] = 0; + return buf; +} +#endif /* NM_IGNORED */ + +char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { + static const struct { + const char *suffix; + usec_t usec; + } table[] = { + { "y", USEC_PER_YEAR }, + { "month", USEC_PER_MONTH }, + { "w", USEC_PER_WEEK }, + { "d", USEC_PER_DAY }, + { "h", USEC_PER_HOUR }, + { "min", USEC_PER_MINUTE }, + { "s", USEC_PER_SEC }, + { "ms", USEC_PER_MSEC }, + { "us", 1 }, + }; + + unsigned i; + char *p = buf; + bool something = false; + + assert(buf); + assert(l > 0); + + if (t == USEC_INFINITY) { + strncpy(p, "infinity", l-1); + p[l-1] = 0; + return p; + } + + if (t <= 0) { + strncpy(p, "0", l-1); + p[l-1] = 0; + return p; + } + + /* The result of this function can be parsed with parse_sec */ + + for (i = 0; i < ELEMENTSOF(table); i++) { + int k = 0; + size_t n; + bool done = false; + usec_t a, b; + + if (t <= 0) + break; + + if (t < accuracy && something) + break; + + if (t < table[i].usec) + continue; + + if (l <= 1) + break; + + a = t / table[i].usec; + b = t % table[i].usec; + + /* Let's see if we should shows this in dot notation */ + if (t < USEC_PER_MINUTE && b > 0) { + usec_t cc; + int j; + + j = 0; + for (cc = table[i].usec; cc > 1; cc /= 10) + j++; + + for (cc = accuracy; cc > 1; cc /= 10) { + b /= 10; + j--; + } + + if (j > 0) { + k = snprintf(p, l, + "%s"USEC_FMT".%0*llu%s", + p > buf ? " " : "", + a, + j, + (unsigned long long) b, + table[i].suffix); + + t = 0; + done = true; + } + } + + /* No? Then let's show it normally */ + if (!done) { + k = snprintf(p, l, + "%s"USEC_FMT"%s", + p > buf ? " " : "", + a, + table[i].suffix); + + t = b; + } + + n = MIN((size_t) k, l); + + l -= n; + p += n; + + something = true; + } + + *p = 0; + + return buf; +} + +#if 0 /* NM_IGNORED */ +void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t) { + + assert(f); + assert(name); + assert(t); + + if (!dual_timestamp_is_set(t)) + return; + + fprintf(f, "%s="USEC_FMT" "USEC_FMT"\n", + name, + t->realtime, + t->monotonic); +} + +int dual_timestamp_deserialize(const char *value, dual_timestamp *t) { + unsigned long long a, b; + + assert(value); + assert(t); + + if (sscanf(value, "%llu %llu", &a, &b) != 2) { + log_debug("Failed to parse finish timestamp value %s.", value); + return -EINVAL; + } + + t->realtime = a; + t->monotonic = b; + + return 0; +} + +int parse_timestamp(const char *t, usec_t *usec) { + static const struct { + const char *name; + const int nr; + } day_nr[] = { + { "Sunday", 0 }, + { "Sun", 0 }, + { "Monday", 1 }, + { "Mon", 1 }, + { "Tuesday", 2 }, + { "Tue", 2 }, + { "Wednesday", 3 }, + { "Wed", 3 }, + { "Thursday", 4 }, + { "Thu", 4 }, + { "Friday", 5 }, + { "Fri", 5 }, + { "Saturday", 6 }, + { "Sat", 6 }, + }; + + const char *k; + const char *utc; + struct tm tm, copy; + time_t x; + usec_t x_usec, plus = 0, minus = 0, ret; + int r, weekday = -1; + unsigned i; + + /* + * Allowed syntaxes: + * + * 2012-09-22 16:34:22 + * 2012-09-22 16:34 (seconds will be set to 0) + * 2012-09-22 (time will be set to 00:00:00) + * 16:34:22 (date will be set to today) + * 16:34 (date will be set to today, seconds to 0) + * now + * yesterday (time is set to 00:00:00) + * today (time is set to 00:00:00) + * tomorrow (time is set to 00:00:00) + * +5min + * -5days + * @2147483647 (seconds since epoch) + * + */ + + assert(t); + assert(usec); + + if (t[0] == '@') + return parse_sec(t + 1, usec); + + ret = now(CLOCK_REALTIME); + + if (streq(t, "now")) + goto finish; + + else if (t[0] == '+') { + r = parse_sec(t+1, &plus); + if (r < 0) + return r; + + goto finish; + + } else if (t[0] == '-') { + r = parse_sec(t+1, &minus); + if (r < 0) + return r; + + goto finish; + + } else if ((k = endswith(t, " ago"))) { + t = strndupa(t, k - t); + + r = parse_sec(t, &minus); + if (r < 0) + return r; + + goto finish; + + } else if ((k = endswith(t, " left"))) { + t = strndupa(t, k - t); + + r = parse_sec(t, &plus); + if (r < 0) + return r; + + goto finish; + } + + utc = endswith_no_case(t, " UTC"); + if (utc) + t = strndupa(t, utc - t); + + x = ret / USEC_PER_SEC; + x_usec = 0; + + assert_se(localtime_or_gmtime_r(&x, &tm, utc)); + tm.tm_isdst = -1; + + if (streq(t, "today")) { + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto from_tm; + + } else if (streq(t, "yesterday")) { + tm.tm_mday --; + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto from_tm; + + } else if (streq(t, "tomorrow")) { + tm.tm_mday ++; + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto from_tm; + } + + + for (i = 0; i < ELEMENTSOF(day_nr); i++) { + size_t skip; + + if (!startswith_no_case(t, day_nr[i].name)) + continue; + + skip = strlen(day_nr[i].name); + if (t[skip] != ' ') + continue; + + weekday = day_nr[i].nr; + t += skip + 1; + break; + } + + copy = tm; + k = strptime(t, "%y-%m-%d %H:%M:%S", &tm); + if (k) { + if (*k == '.') + goto parse_usec; + else if (*k == 0) + goto from_tm; + } + + tm = copy; + k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm); + if (k) { + if (*k == '.') + goto parse_usec; + else if (*k == 0) + goto from_tm; + } + + tm = copy; + k = strptime(t, "%y-%m-%d %H:%M", &tm); + if (k && *k == 0) { + tm.tm_sec = 0; + goto from_tm; + } + + tm = copy; + k = strptime(t, "%Y-%m-%d %H:%M", &tm); + if (k && *k == 0) { + tm.tm_sec = 0; + goto from_tm; + } + + tm = copy; + k = strptime(t, "%y-%m-%d", &tm); + if (k && *k == 0) { + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto from_tm; + } + + tm = copy; + k = strptime(t, "%Y-%m-%d", &tm); + if (k && *k == 0) { + tm.tm_sec = tm.tm_min = tm.tm_hour = 0; + goto from_tm; + } + + tm = copy; + k = strptime(t, "%H:%M:%S", &tm); + if (k) { + if (*k == '.') + goto parse_usec; + else if (*k == 0) + goto from_tm; + } + + tm = copy; + k = strptime(t, "%H:%M", &tm); + if (k && *k == 0) { + tm.tm_sec = 0; + goto from_tm; + } + + return -EINVAL; + +parse_usec: + { + unsigned add; + + k++; + r = parse_fractional_part_u(&k, 6, &add); + if (r < 0) + return -EINVAL; + + if (*k) + return -EINVAL; + + x_usec = add; + + } + +from_tm: + x = mktime_or_timegm(&tm, utc); + if (x == (time_t) -1) + return -EINVAL; + + if (weekday >= 0 && tm.tm_wday != weekday) + return -EINVAL; + + ret = (usec_t) x * USEC_PER_SEC + x_usec; + +finish: + ret += plus; + if (ret > minus) + ret -= minus; + else + ret = 0; + + *usec = ret; + + return 0; +} + +int parse_time(const char *t, usec_t *usec, usec_t default_unit) { + + static const struct { + const char *suffix; + usec_t usec; + } table[] = { + { "seconds", USEC_PER_SEC }, + { "second", USEC_PER_SEC }, + { "sec", USEC_PER_SEC }, + { "s", USEC_PER_SEC }, + { "minutes", USEC_PER_MINUTE }, + { "minute", USEC_PER_MINUTE }, + { "min", USEC_PER_MINUTE }, + { "months", USEC_PER_MONTH }, + { "month", USEC_PER_MONTH }, + { "M", USEC_PER_MONTH }, + { "msec", USEC_PER_MSEC }, + { "ms", USEC_PER_MSEC }, + { "m", USEC_PER_MINUTE }, + { "hours", USEC_PER_HOUR }, + { "hour", USEC_PER_HOUR }, + { "hr", USEC_PER_HOUR }, + { "h", USEC_PER_HOUR }, + { "days", USEC_PER_DAY }, + { "day", USEC_PER_DAY }, + { "d", USEC_PER_DAY }, + { "weeks", USEC_PER_WEEK }, + { "week", USEC_PER_WEEK }, + { "w", USEC_PER_WEEK }, + { "years", USEC_PER_YEAR }, + { "year", USEC_PER_YEAR }, + { "y", USEC_PER_YEAR }, + { "usec", 1ULL }, + { "us", 1ULL }, + }; + + const char *p, *s; + usec_t r = 0; + bool something = false; + + assert(t); + assert(usec); + assert(default_unit > 0); + + p = t; + + p += strspn(p, WHITESPACE); + s = startswith(p, "infinity"); + if (s) { + s += strspn(s, WHITESPACE); + if (*s != 0) + return -EINVAL; + + *usec = USEC_INFINITY; + return 0; + } + + for (;;) { + long long l, z = 0; + char *e; + unsigned i, n = 0; + usec_t multiplier, k; + + p += strspn(p, WHITESPACE); + + if (*p == 0) { + if (!something) + return -EINVAL; + + break; + } + + errno = 0; + l = strtoll(p, &e, 10); + + if (errno > 0) + return -errno; + + if (l < 0) + return -ERANGE; + + if (*e == '.') { + char *b = e + 1; + + errno = 0; + z = strtoll(b, &e, 10); + if (errno > 0) + return -errno; + + if (z < 0) + return -ERANGE; + + if (e == b) + return -EINVAL; + + n = e - b; + + } else if (e == p) + return -EINVAL; + + e += strspn(e, WHITESPACE); + + for (i = 0; i < ELEMENTSOF(table); i++) + if (startswith(e, table[i].suffix)) { + multiplier = table[i].usec; + p = e + strlen(table[i].suffix); + break; + } + + if (i >= ELEMENTSOF(table)) { + multiplier = default_unit; + p = e; + } + + something = true; + + k = (usec_t) z * multiplier; + + for (; n > 0; n--) + k /= 10; + + r += (usec_t) l * multiplier + k; + } + + *usec = r; + + return 0; +} + +int parse_sec(const char *t, usec_t *usec) { + return parse_time(t, usec, USEC_PER_SEC); +} + +int parse_nsec(const char *t, nsec_t *nsec) { + static const struct { + const char *suffix; + nsec_t nsec; + } table[] = { + { "seconds", NSEC_PER_SEC }, + { "second", NSEC_PER_SEC }, + { "sec", NSEC_PER_SEC }, + { "s", NSEC_PER_SEC }, + { "minutes", NSEC_PER_MINUTE }, + { "minute", NSEC_PER_MINUTE }, + { "min", NSEC_PER_MINUTE }, + { "months", NSEC_PER_MONTH }, + { "month", NSEC_PER_MONTH }, + { "msec", NSEC_PER_MSEC }, + { "ms", NSEC_PER_MSEC }, + { "m", NSEC_PER_MINUTE }, + { "hours", NSEC_PER_HOUR }, + { "hour", NSEC_PER_HOUR }, + { "hr", NSEC_PER_HOUR }, + { "h", NSEC_PER_HOUR }, + { "days", NSEC_PER_DAY }, + { "day", NSEC_PER_DAY }, + { "d", NSEC_PER_DAY }, + { "weeks", NSEC_PER_WEEK }, + { "week", NSEC_PER_WEEK }, + { "w", NSEC_PER_WEEK }, + { "years", NSEC_PER_YEAR }, + { "year", NSEC_PER_YEAR }, + { "y", NSEC_PER_YEAR }, + { "usec", NSEC_PER_USEC }, + { "us", NSEC_PER_USEC }, + { "nsec", 1ULL }, + { "ns", 1ULL }, + { "", 1ULL }, /* default is nsec */ + }; + + const char *p, *s; + nsec_t r = 0; + bool something = false; + + assert(t); + assert(nsec); + + p = t; + + p += strspn(p, WHITESPACE); + s = startswith(p, "infinity"); + if (s) { + s += strspn(s, WHITESPACE); + if (*s != 0) + return -EINVAL; + + *nsec = NSEC_INFINITY; + return 0; + } + + for (;;) { + long long l, z = 0; + char *e; + unsigned i, n = 0; + + p += strspn(p, WHITESPACE); + + if (*p == 0) { + if (!something) + return -EINVAL; + + break; + } + + errno = 0; + l = strtoll(p, &e, 10); + + if (errno > 0) + return -errno; + + if (l < 0) + return -ERANGE; + + if (*e == '.') { + char *b = e + 1; + + errno = 0; + z = strtoll(b, &e, 10); + if (errno > 0) + return -errno; + + if (z < 0) + return -ERANGE; + + if (e == b) + return -EINVAL; + + n = e - b; + + } else if (e == p) + return -EINVAL; + + e += strspn(e, WHITESPACE); + + for (i = 0; i < ELEMENTSOF(table); i++) + if (startswith(e, table[i].suffix)) { + nsec_t k = (nsec_t) z * table[i].nsec; + + for (; n > 0; n--) + k /= 10; + + r += (nsec_t) l * table[i].nsec + k; + p = e + strlen(table[i].suffix); + + something = true; + break; + } + + if (i >= ELEMENTSOF(table)) + return -EINVAL; + + } + + *nsec = r; + + return 0; +} + +bool ntp_synced(void) { + struct timex txc = {}; + + if (adjtimex(&txc) < 0) + return false; + + if (txc.status & STA_UNSYNC) + return false; + + return true; +} + +int get_timezones(char ***ret) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_strv_free_ char **zones = NULL; + size_t n_zones = 0, n_allocated = 0; + + assert(ret); + + zones = strv_new("UTC", NULL); + if (!zones) + return -ENOMEM; + + n_allocated = 2; + n_zones = 1; + + f = fopen("/usr/share/zoneinfo/zone.tab", "re"); + if (f) { + char l[LINE_MAX]; + + FOREACH_LINE(l, f, return -errno) { + char *p, *w; + size_t k; + + p = strstrip(l); + + if (isempty(p) || *p == '#') + continue; + + /* Skip over country code */ + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Skip over coordinates */ + p += strcspn(p, WHITESPACE); + p += strspn(p, WHITESPACE); + + /* Found timezone name */ + k = strcspn(p, WHITESPACE); + if (k <= 0) + continue; + + w = strndup(p, k); + if (!w) + return -ENOMEM; + + if (!GREEDY_REALLOC(zones, n_allocated, n_zones + 2)) { + free(w); + return -ENOMEM; + } + + zones[n_zones++] = w; + zones[n_zones] = NULL; + } + + strv_sort(zones); + + } else if (errno != ENOENT) + return -errno; + + *ret = zones; + zones = NULL; + + return 0; +} +#endif /* NM_IGNORED */ + +bool timezone_is_valid(const char *name) { + bool slash = false; + const char *p, *t; + struct stat st; + + if (isempty(name)) + return false; + + if (name[0] == '/') + return false; + + for (p = name; *p; p++) { + if (!(*p >= '0' && *p <= '9') && + !(*p >= 'a' && *p <= 'z') && + !(*p >= 'A' && *p <= 'Z') && + !(*p == '-' || *p == '_' || *p == '+' || *p == '/')) + return false; + + if (*p == '/') { + + if (slash) + return false; + + slash = true; + } else + slash = false; + } + + if (slash) + return false; + + t = strjoina("/usr/share/zoneinfo/", name); + if (stat(t, &st) < 0) + return false; + + if (!S_ISREG(st.st_mode)) + return false; + + return true; +} + +clockid_t clock_boottime_or_monotonic(void) { + static clockid_t clock = -1; + int fd; + + if (clock != -1) + return clock; + + fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC); + if (fd < 0) + clock = CLOCK_MONOTONIC; + else { + safe_close(fd); + clock = CLOCK_BOOTTIME; + } + + return clock; +} + +#if 0 /* NM_IGNORED */ +int get_timezone(char **tz) { + _cleanup_free_ char *t = NULL; + const char *e; + char *z; + int r; + + r = readlink_malloc("/etc/localtime", &t); + if (r < 0) + return r; /* returns EINVAL if not a symlink */ + + e = path_startswith(t, "/usr/share/zoneinfo/"); + if (!e) + e = path_startswith(t, "../usr/share/zoneinfo/"); + if (!e) + return -EINVAL; + + if (!timezone_is_valid(e)) + return -EINVAL; + + z = strdup(e); + if (!z) + return -ENOMEM; + + *tz = z; + return 0; +} + +time_t mktime_or_timegm(struct tm *tm, bool utc) { + return utc ? timegm(tm) : mktime(tm); +} + +struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc) { + return utc ? gmtime_r(t, tm) : localtime_r(t, tm); +} + +unsigned long usec_to_jiffies(usec_t u) { + static thread_local unsigned long hz = 0; + long r; + + if (hz == 0) { + r = sysconf(_SC_CLK_TCK); + + assert(r > 0); + hz = (unsigned long) r; + } + + return DIV_ROUND_UP(u , USEC_PER_SEC / hz); +} +#endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/time-util.h b/src/systemd/src/basic/time-util.h new file mode 100644 index 00000000..760ac2a0 --- /dev/null +++ b/src/systemd/src/basic/time-util.h @@ -0,0 +1,131 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include + +typedef uint64_t usec_t; +typedef uint64_t nsec_t; + +#define NSEC_FMT "%" PRIu64 +#define USEC_FMT "%" PRIu64 + +#include "macro.h" + +typedef struct dual_timestamp { + usec_t realtime; + usec_t monotonic; +} dual_timestamp; + +#define USEC_INFINITY ((usec_t) -1) +#define NSEC_INFINITY ((nsec_t) -1) + +#define MSEC_PER_SEC 1000ULL +#define USEC_PER_SEC ((usec_t) 1000000ULL) +#define USEC_PER_MSEC ((usec_t) 1000ULL) +#define NSEC_PER_SEC ((nsec_t) 1000000000ULL) +#define NSEC_PER_MSEC ((nsec_t) 1000000ULL) +#define NSEC_PER_USEC ((nsec_t) 1000ULL) + +#define USEC_PER_MINUTE ((usec_t) (60ULL*USEC_PER_SEC)) +#define NSEC_PER_MINUTE ((nsec_t) (60ULL*NSEC_PER_SEC)) +#define USEC_PER_HOUR ((usec_t) (60ULL*USEC_PER_MINUTE)) +#define NSEC_PER_HOUR ((nsec_t) (60ULL*NSEC_PER_MINUTE)) +#define USEC_PER_DAY ((usec_t) (24ULL*USEC_PER_HOUR)) +#define NSEC_PER_DAY ((nsec_t) (24ULL*NSEC_PER_HOUR)) +#define USEC_PER_WEEK ((usec_t) (7ULL*USEC_PER_DAY)) +#define NSEC_PER_WEEK ((nsec_t) (7ULL*NSEC_PER_DAY)) +#define USEC_PER_MONTH ((usec_t) (2629800ULL*USEC_PER_SEC)) +#define NSEC_PER_MONTH ((nsec_t) (2629800ULL*NSEC_PER_SEC)) +#define USEC_PER_YEAR ((usec_t) (31557600ULL*USEC_PER_SEC)) +#define NSEC_PER_YEAR ((nsec_t) (31557600ULL*NSEC_PER_SEC)) + +#define FORMAT_TIMESTAMP_MAX ((4*4+1)+11+9+4+1) /* weekdays can be unicode */ +#define FORMAT_TIMESTAMP_WIDTH 28 /* when outputting, assume this width */ +#define FORMAT_TIMESTAMP_RELATIVE_MAX 256 +#define FORMAT_TIMESPAN_MAX 64 + +#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) + +#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL }) + +usec_t now(clockid_t clock); +nsec_t now_nsec(clockid_t clock); + +dual_timestamp* dual_timestamp_get(dual_timestamp *ts); +dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u); +dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u); +dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, usec_t u); + +static inline bool dual_timestamp_is_set(dual_timestamp *ts) { + return ((ts->realtime > 0 && ts->realtime != USEC_INFINITY) || + (ts->monotonic > 0 && ts->monotonic != USEC_INFINITY)); +} + +usec_t timespec_load(const struct timespec *ts) _pure_; +struct timespec *timespec_store(struct timespec *ts, usec_t u); + +usec_t timeval_load(const struct timeval *tv) _pure_; +struct timeval *timeval_store(struct timeval *tv, usec_t u); + +nsec_t timespec_load_nsec(const struct timespec *ts) _pure_; + +char *format_timestamp(char *buf, size_t l, usec_t t); +char *format_timestamp_utc(char *buf, size_t l, usec_t t); +char *format_timestamp_us(char *buf, size_t l, usec_t t); +char *format_timestamp_us_utc(char *buf, size_t l, usec_t t); +char *format_timestamp_relative(char *buf, size_t l, usec_t t); +char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy); + +void dual_timestamp_serialize(FILE *f, const char *name, dual_timestamp *t); +int dual_timestamp_deserialize(const char *value, dual_timestamp *t); + +int parse_timestamp(const char *t, usec_t *usec); + +int parse_sec(const char *t, usec_t *usec); +int parse_time(const char *t, usec_t *usec, usec_t default_unit); +int parse_nsec(const char *t, nsec_t *nsec); + +bool ntp_synced(void); + +int get_timezones(char ***l); +bool timezone_is_valid(const char *name); + +clockid_t clock_boottime_or_monotonic(void); + +#define xstrftime(buf, fmt, tm) \ + assert_message_se(strftime(buf, ELEMENTSOF(buf), fmt, tm) > 0, \ + "xstrftime: " #buf "[] must be big enough") + +int get_timezone(char **timezone); + +time_t mktime_or_timegm(struct tm *tm, bool utc); +struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc); + +unsigned long usec_to_jiffies(usec_t usec); diff --git a/src/systemd/src/basic/umask-util.h b/src/systemd/src/basic/umask-util.h new file mode 100644 index 00000000..aada0540 --- /dev/null +++ b/src/systemd/src/basic/umask-util.h @@ -0,0 +1,50 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include + +#include "macro.h" + +static inline void umaskp(mode_t *u) { + umask(*u); +} + +#define _cleanup_umask_ _cleanup_(umaskp) + +struct _umask_struct_ { + mode_t mask; + bool quit; +}; + +static inline void _reset_umask_(struct _umask_struct_ *s) { + umask(s->mask); +}; + +#define RUN_WITH_UMASK(mask) \ + for (_cleanup_(_reset_umask_) struct _umask_struct_ _saved_umask_ = { umask(mask), false }; \ + !_saved_umask_.quit ; \ + _saved_umask_.quit = true) diff --git a/src/systemd/src/basic/unaligned.h b/src/systemd/src/basic/unaligned.h new file mode 100644 index 00000000..597c890d --- /dev/null +++ b/src/systemd/src/basic/unaligned.h @@ -0,0 +1,115 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +/* BE */ + +static inline uint16_t unaligned_read_be16(const void *_u) { + const uint8_t *u = _u; + + return (((uint16_t) u[0]) << 8) | + ((uint16_t) u[1]); +} + +static inline uint32_t unaligned_read_be32(const void *_u) { + const uint8_t *u = _u; + + return (((uint32_t) unaligned_read_be16(u)) << 16) | + ((uint32_t) unaligned_read_be16(u + 2)); +} + +static inline uint64_t unaligned_read_be64(const void *_u) { + const uint8_t *u = _u; + + return (((uint64_t) unaligned_read_be32(u)) << 32) | + ((uint64_t) unaligned_read_be32(u + 4)); +} + +static inline void unaligned_write_be16(void *_u, uint16_t a) { + uint8_t *u = _u; + + u[0] = (uint8_t) (a >> 8); + u[1] = (uint8_t) a; +} + +static inline void unaligned_write_be32(void *_u, uint32_t a) { + uint8_t *u = _u; + + unaligned_write_be16(u, (uint16_t) (a >> 16)); + unaligned_write_be16(u + 2, (uint16_t) a); +} + +static inline void unaligned_write_be64(void *_u, uint64_t a) { + uint8_t *u = _u; + + unaligned_write_be32(u, (uint32_t) (a >> 32)); + unaligned_write_be32(u + 4, (uint32_t) a); +} + +/* LE */ + +static inline uint16_t unaligned_read_le16(const void *_u) { + const uint8_t *u = _u; + + return (((uint16_t) u[1]) << 8) | + ((uint16_t) u[0]); +} + +static inline uint32_t unaligned_read_le32(const void *_u) { + const uint8_t *u = _u; + + return (((uint32_t) unaligned_read_le16(u + 2)) << 16) | + ((uint32_t) unaligned_read_le16(u)); +} + +static inline uint64_t unaligned_read_le64(const void *_u) { + const uint8_t *u = _u; + + return (((uint64_t) unaligned_read_le32(u + 4)) << 32) | + ((uint64_t) unaligned_read_le32(u)); +} + +static inline void unaligned_write_le16(void *_u, uint16_t a) { + uint8_t *u = _u; + + u[0] = (uint8_t) a; + u[1] = (uint8_t) (a >> 8); +} + +static inline void unaligned_write_le32(void *_u, uint32_t a) { + uint8_t *u = _u; + + unaligned_write_le16(u, (uint16_t) a); + unaligned_write_le16(u + 2, (uint16_t) (a >> 16)); +} + +static inline void unaligned_write_le64(void *_u, uint64_t a) { + uint8_t *u = _u; + + unaligned_write_le32(u, (uint32_t) a); + unaligned_write_le32(u + 4, (uint32_t) (a >> 32)); +} diff --git a/src/systemd/src/basic/utf8.c b/src/systemd/src/basic/utf8.c new file mode 100644 index 00000000..20beb6ea --- /dev/null +++ b/src/systemd/src/basic/utf8.c @@ -0,0 +1,405 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2008-2011 Kay Sievers + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +/* Parts of this file are based on the GLIB utf8 validation functions. The + * original license text follows. */ + +/* gutf8.c - Operations on UTF-8 strings. + * + * Copyright (C) 1999 Tom Tromey + * Copyright (C) 2000 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "alloc-util.h" +#include "hexdecoct.h" +#include "macro.h" +#include "utf8.h" + +bool unichar_is_valid(uint32_t ch) { + + if (ch >= 0x110000) /* End of unicode space */ + return false; + if ((ch & 0xFFFFF800) == 0xD800) /* Reserved area for UTF-16 */ + return false; + if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) /* Reserved */ + return false; + if ((ch & 0xFFFE) == 0xFFFE) /* BOM (Byte Order Mark) */ + return false; + + return true; +} + +static bool unichar_is_control(uint32_t ch) { + + /* + 0 to ' '-1 is the C0 range. + DEL=0x7F, and DEL+1 to 0x9F is C1 range. + '\t' is in C0 range, but more or less harmless and commonly used. + */ + + return (ch < ' ' && ch != '\t' && ch != '\n') || + (0x7F <= ch && ch <= 0x9F); +} + +/* count of characters used to encode one unicode char */ +static int utf8_encoded_expected_len(const char *str) { + unsigned char c; + + assert(str); + + c = (unsigned char) str[0]; + if (c < 0x80) + return 1; + if ((c & 0xe0) == 0xc0) + return 2; + if ((c & 0xf0) == 0xe0) + return 3; + if ((c & 0xf8) == 0xf0) + return 4; + if ((c & 0xfc) == 0xf8) + return 5; + if ((c & 0xfe) == 0xfc) + return 6; + + return 0; +} + +/* decode one unicode char */ +int utf8_encoded_to_unichar(const char *str) { + int unichar, len, i; + + assert(str); + + len = utf8_encoded_expected_len(str); + + switch (len) { + case 1: + return (int)str[0]; + case 2: + unichar = str[0] & 0x1f; + break; + case 3: + unichar = (int)str[0] & 0x0f; + break; + case 4: + unichar = (int)str[0] & 0x07; + break; + case 5: + unichar = (int)str[0] & 0x03; + break; + case 6: + unichar = (int)str[0] & 0x01; + break; + default: + return -EINVAL; + } + + for (i = 1; i < len; i++) { + if (((int)str[i] & 0xc0) != 0x80) + return -EINVAL; + unichar <<= 6; + unichar |= (int)str[i] & 0x3f; + } + + return unichar; +} + +bool utf8_is_printable_newline(const char* str, size_t length, bool newline) { + const char *p; + + assert(str); + + for (p = str; length;) { + int encoded_len, val; + + encoded_len = utf8_encoded_valid_unichar(p); + if (encoded_len < 0 || + (size_t) encoded_len > length) + return false; + + val = utf8_encoded_to_unichar(p); + if (val < 0 || + unichar_is_control(val) || + (!newline && val == '\n')) + return false; + + length -= encoded_len; + p += encoded_len; + } + + return true; +} + +const char *utf8_is_valid(const char *str) { + const uint8_t *p; + + assert(str); + + for (p = (const uint8_t*) str; *p; ) { + int len; + + len = utf8_encoded_valid_unichar((const char *)p); + if (len < 0) + return NULL; + + p += len; + } + + return str; +} + +char *utf8_escape_invalid(const char *str) { + char *p, *s; + + assert(str); + + p = s = malloc(strlen(str) * 4 + 1); + if (!p) + return NULL; + + while (*str) { + int len; + + len = utf8_encoded_valid_unichar(str); + if (len > 0) { + s = mempcpy(s, str, len); + str += len; + } else { + s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER); + str += 1; + } + } + + *s = '\0'; + + return p; +} + +char *utf8_escape_non_printable(const char *str) { + char *p, *s; + + assert(str); + + p = s = malloc(strlen(str) * 4 + 1); + if (!p) + return NULL; + + while (*str) { + int len; + + len = utf8_encoded_valid_unichar(str); + if (len > 0) { + if (utf8_is_printable(str, len)) { + s = mempcpy(s, str, len); + str += len; + } else { + while (len > 0) { + *(s++) = '\\'; + *(s++) = 'x'; + *(s++) = hexchar((int) *str >> 4); + *(s++) = hexchar((int) *str); + + str += 1; + len --; + } + } + } else { + s = stpcpy(s, UTF8_REPLACEMENT_CHARACTER); + str += 1; + } + } + + *s = '\0'; + + return p; +} + +char *ascii_is_valid(const char *str) { + const char *p; + + assert(str); + + for (p = str; *p; p++) + if ((unsigned char) *p >= 128) + return NULL; + + return (char*) str; +} + +/** + * utf8_encode_unichar() - Encode single UCS-4 character as UTF-8 + * @out_utf8: output buffer of at least 4 bytes or NULL + * @g: UCS-4 character to encode + * + * This encodes a single UCS-4 character as UTF-8 and writes it into @out_utf8. + * The length of the character is returned. It is not zero-terminated! If the + * output buffer is NULL, only the length is returned. + * + * Returns: The length in bytes that the UTF-8 representation does or would + * occupy. + */ +size_t utf8_encode_unichar(char *out_utf8, uint32_t g) { + + if (g < (1 << 7)) { + if (out_utf8) + out_utf8[0] = g & 0x7f; + return 1; + } else if (g < (1 << 11)) { + if (out_utf8) { + out_utf8[0] = 0xc0 | ((g >> 6) & 0x1f); + out_utf8[1] = 0x80 | (g & 0x3f); + } + return 2; + } else if (g < (1 << 16)) { + if (out_utf8) { + out_utf8[0] = 0xe0 | ((g >> 12) & 0x0f); + out_utf8[1] = 0x80 | ((g >> 6) & 0x3f); + out_utf8[2] = 0x80 | (g & 0x3f); + } + return 3; + } else if (g < (1 << 21)) { + if (out_utf8) { + out_utf8[0] = 0xf0 | ((g >> 18) & 0x07); + out_utf8[1] = 0x80 | ((g >> 12) & 0x3f); + out_utf8[2] = 0x80 | ((g >> 6) & 0x3f); + out_utf8[3] = 0x80 | (g & 0x3f); + } + return 4; + } + + return 0; +} + +char *utf16_to_utf8(const void *s, size_t length) { + const uint8_t *f; + char *r, *t; + + r = new(char, (length * 4 + 1) / 2 + 1); + if (!r) + return NULL; + + f = s; + t = r; + + while (f < (const uint8_t*) s + length) { + uint16_t w1, w2; + + /* see RFC 2781 section 2.2 */ + + w1 = f[1] << 8 | f[0]; + f += 2; + + if (!utf16_is_surrogate(w1)) { + t += utf8_encode_unichar(t, w1); + + continue; + } + + if (utf16_is_trailing_surrogate(w1)) + continue; + else if (f >= (const uint8_t*) s + length) + break; + + w2 = f[1] << 8 | f[0]; + f += 2; + + if (!utf16_is_trailing_surrogate(w2)) { + f -= 2; + continue; + } + + t += utf8_encode_unichar(t, utf16_surrogate_pair_to_unichar(w1, w2)); + } + + *t = 0; + return r; +} + +/* expected size used to encode one unicode char */ +static int utf8_unichar_to_encoded_len(int unichar) { + + if (unichar < 0x80) + return 1; + if (unichar < 0x800) + return 2; + if (unichar < 0x10000) + return 3; + if (unichar < 0x200000) + return 4; + if (unichar < 0x4000000) + return 5; + + return 6; +} + +/* validate one encoded unicode char and return its length */ +int utf8_encoded_valid_unichar(const char *str) { + int len, unichar, i; + + assert(str); + + len = utf8_encoded_expected_len(str); + if (len == 0) + return -EINVAL; + + /* ascii is valid */ + if (len == 1) + return 1; + + /* check if expected encoded chars are available */ + for (i = 0; i < len; i++) + if ((str[i] & 0x80) != 0x80) + return -EINVAL; + + unichar = utf8_encoded_to_unichar(str); + + /* check if encoded length matches encoded value */ + if (utf8_unichar_to_encoded_len(unichar) != len) + return -EINVAL; + + /* check if value has valid range */ + if (!unichar_is_valid(unichar)) + return -EINVAL; + + return len; +} diff --git a/src/systemd/src/basic/utf8.h b/src/systemd/src/basic/utf8.h new file mode 100644 index 00000000..32172c31 --- /dev/null +++ b/src/systemd/src/basic/utf8.h @@ -0,0 +1,61 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include + +#include "macro.h" + +#define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd" + +bool unichar_is_valid(uint32_t c); + +const char *utf8_is_valid(const char *s) _pure_; +char *ascii_is_valid(const char *s) _pure_; + +bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pure_; +#define utf8_is_printable(str, length) utf8_is_printable_newline(str, length, true) + +char *utf8_escape_invalid(const char *s); +char *utf8_escape_non_printable(const char *str); + +size_t utf8_encode_unichar(char *out_utf8, uint32_t g); +char *utf16_to_utf8(const void *s, size_t length); + +int utf8_encoded_valid_unichar(const char *str); +int utf8_encoded_to_unichar(const char *str); + +static inline bool utf16_is_surrogate(uint16_t c) { + return (0xd800 <= c && c <= 0xdfff); +} + +static inline bool utf16_is_trailing_surrogate(uint16_t c) { + return (0xdc00 <= c && c <= 0xdfff); +} + +static inline uint32_t utf16_surrogate_pair_to_unichar(uint16_t lead, uint16_t trail) { + return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000; +} diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c new file mode 100644 index 00000000..43e453ee --- /dev/null +++ b/src/systemd/src/basic/util.c @@ -0,0 +1,813 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "alloc-util.h" +#if 0 /* NM_IGNORED */ +#include "build.h" +#include "def.h" +#include "dirent-util.h" +#endif /* NM_IGNORED */ +#include "fd-util.h" +#include "fileio.h" +#if 0 /* NM_IGNORED */ +#include "formats-util.h" +#endif /* NM_IGNORED */ +#include "hashmap.h" +#include "hostname-util.h" +#include "log.h" +#include "macro.h" +#if 0 /* NM_IGNORED */ +#include "missing.h" +#endif /* NM_IGNORED */ +#include "parse-util.h" +#include "path-util.h" +#if 0 /* NM_IGNORED */ +#include "process-util.h" +#endif /* NM_IGNORED */ +#include "set.h" +#if 0 /* NM_IGNORED */ +#include "signal-util.h" +#include "stat-util.h" +#endif /* NM_IGNORED */ +#include "string-util.h" +#include "strv.h" +#include "time-util.h" +#if 0 /* NM_IGNORED */ +#include "user-util.h" +#endif /* NM_IGNORED */ +#include "util.h" + +/* Put this test here for a lack of better place */ +assert_cc(EAGAIN == EWOULDBLOCK); + +#if 0 /* NM_IGNORED */ +int saved_argc = 0; +char **saved_argv = NULL; +#endif /* NM_IGNORED */ + +size_t page_size(void) { + static thread_local size_t pgsz = 0; + long r; + + if (_likely_(pgsz > 0)) + return pgsz; + + r = sysconf(_SC_PAGESIZE); + assert(r > 0); + + pgsz = (size_t) r; + return pgsz; +} + +#if 0 /* NM_IGNORED */ +static int do_execute(char **directories, usec_t timeout, char *argv[]) { + _cleanup_hashmap_free_free_ Hashmap *pids = NULL; + _cleanup_set_free_free_ Set *seen = NULL; + char **directory; + + /* We fork this all off from a child process so that we can + * somewhat cleanly make use of SIGALRM to set a time limit */ + + (void) reset_all_signal_handlers(); + (void) reset_signal_mask(); + + assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0); + + pids = hashmap_new(NULL); + if (!pids) + return log_oom(); + + seen = set_new(&string_hash_ops); + if (!seen) + return log_oom(); + + STRV_FOREACH(directory, directories) { + _cleanup_closedir_ DIR *d; + struct dirent *de; + + d = opendir(*directory); + if (!d) { + if (errno == ENOENT) + continue; + + return log_error_errno(errno, "Failed to open directory %s: %m", *directory); + } + + FOREACH_DIRENT(de, d, break) { + _cleanup_free_ char *path = NULL; + pid_t pid; + int r; + + if (!dirent_is_file(de)) + continue; + + if (set_contains(seen, de->d_name)) { + log_debug("%1$s/%2$s skipped (%2$s was already seen).", *directory, de->d_name); + continue; + } + + r = set_put_strdup(seen, de->d_name); + if (r < 0) + return log_oom(); + + path = strjoin(*directory, "/", de->d_name, NULL); + if (!path) + return log_oom(); + + if (null_or_empty_path(path)) { + log_debug("%s is empty (a mask).", path); + continue; + } + + pid = fork(); + if (pid < 0) { + log_error_errno(errno, "Failed to fork: %m"); + continue; + } else if (pid == 0) { + char *_argv[2]; + + assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0); + + if (!argv) { + _argv[0] = path; + _argv[1] = NULL; + argv = _argv; + } else + argv[0] = path; + + execv(path, argv); + return log_error_errno(errno, "Failed to execute %s: %m", path); + } + + log_debug("Spawned %s as " PID_FMT ".", path, pid); + + r = hashmap_put(pids, PID_TO_PTR(pid), path); + if (r < 0) + return log_oom(); + path = NULL; + } + } + + /* Abort execution of this process after the timout. We simply + * rely on SIGALRM as default action terminating the process, + * and turn on alarm(). */ + + if (timeout != USEC_INFINITY) + alarm((timeout + USEC_PER_SEC - 1) / USEC_PER_SEC); + + while (!hashmap_isempty(pids)) { + _cleanup_free_ char *path = NULL; + pid_t pid; + + pid = PTR_TO_PID(hashmap_first_key(pids)); + assert(pid > 0); + + path = hashmap_remove(pids, PID_TO_PTR(pid)); + assert(path); + + wait_for_terminate_and_warn(path, pid, true); + } + + return 0; +} + +void execute_directories(const char* const* directories, usec_t timeout, char *argv[]) { + pid_t executor_pid; + int r; + char *name; + char **dirs = (char**) directories; + + assert(!strv_isempty(dirs)); + + name = basename(dirs[0]); + assert(!isempty(name)); + + /* Executes all binaries in the directories in parallel and waits + * for them to finish. Optionally a timeout is applied. If a file + * with the same name exists in more than one directory, the + * earliest one wins. */ + + executor_pid = fork(); + if (executor_pid < 0) { + log_error_errno(errno, "Failed to fork: %m"); + return; + + } else if (executor_pid == 0) { + r = do_execute(dirs, timeout, argv); + _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); + } + + wait_for_terminate_and_warn(name, executor_pid, true); +} + +bool plymouth_running(void) { + return access("/run/plymouth/pid", F_OK) >= 0; +} + +bool display_is_local(const char *display) { + assert(display); + + return + display[0] == ':' && + display[1] >= '0' && + display[1] <= '9'; +} + +int socket_from_display(const char *display, char **path) { + size_t k; + char *f, *c; + + assert(display); + assert(path); + + if (!display_is_local(display)) + return -EINVAL; + + k = strspn(display+1, "0123456789"); + + f = new(char, strlen("/tmp/.X11-unix/X") + k + 1); + if (!f) + return -ENOMEM; + + c = stpcpy(f, "/tmp/.X11-unix/X"); + memcpy(c, display+1, k); + c[k] = 0; + + *path = f; + + return 0; +} + +int block_get_whole_disk(dev_t d, dev_t *ret) { + char *p, *s; + int r; + unsigned n, m; + + assert(ret); + + /* If it has a queue this is good enough for us */ + if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0) + return -ENOMEM; + + r = access(p, F_OK); + free(p); + + if (r >= 0) { + *ret = d; + return 0; + } + + /* If it is a partition find the originating device */ + if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0) + return -ENOMEM; + + r = access(p, F_OK); + free(p); + + if (r < 0) + return -ENOENT; + + /* Get parent dev_t */ + if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0) + return -ENOMEM; + + r = read_one_line_file(p, &s); + free(p); + + if (r < 0) + return r; + + r = sscanf(s, "%u:%u", &m, &n); + free(s); + + if (r != 2) + return -EINVAL; + + /* Only return this if it is really good enough for us. */ + if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0) + return -ENOMEM; + + r = access(p, F_OK); + free(p); + + if (r >= 0) { + *ret = makedev(m, n); + return 0; + } + + return -ENOENT; +} + +bool kexec_loaded(void) { + bool loaded = false; + char *s; + + if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) { + if (s[0] == '1') + loaded = true; + free(s); + } + return loaded; +} + +int prot_from_flags(int flags) { + + switch (flags & O_ACCMODE) { + + case O_RDONLY: + return PROT_READ; + + case O_WRONLY: + return PROT_WRITE; + + case O_RDWR: + return PROT_READ|PROT_WRITE; + + default: + return -EINVAL; + } +} + +int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) { + bool stdout_is_tty, stderr_is_tty; + pid_t parent_pid, agent_pid; + sigset_t ss, saved_ss; + unsigned n, i; + va_list ap; + char **l; + + assert(pid); + assert(path); + + /* Spawns a temporary TTY agent, making sure it goes away when + * we go away */ + + parent_pid = getpid(); + + /* First we temporarily block all signals, so that the new + * child has them blocked initially. This way, we can be sure + * that SIGTERMs are not lost we might send to the agent. */ + assert_se(sigfillset(&ss) >= 0); + assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0); + + agent_pid = fork(); + if (agent_pid < 0) { + assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0); + return -errno; + } + + if (agent_pid != 0) { + assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0); + *pid = agent_pid; + return 0; + } + + /* In the child: + * + * Make sure the agent goes away when the parent dies */ + if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) + _exit(EXIT_FAILURE); + + /* Make sure we actually can kill the agent, if we need to, in + * case somebody invoked us from a shell script that trapped + * SIGTERM or so... */ + (void) reset_all_signal_handlers(); + (void) reset_signal_mask(); + + /* Check whether our parent died before we were able + * to set the death signal and unblock the signals */ + if (getppid() != parent_pid) + _exit(EXIT_SUCCESS); + + /* Don't leak fds to the agent */ + close_all_fds(except, n_except); + + stdout_is_tty = isatty(STDOUT_FILENO); + stderr_is_tty = isatty(STDERR_FILENO); + + if (!stdout_is_tty || !stderr_is_tty) { + int fd; + + /* Detach from stdout/stderr. and reopen + * /dev/tty for them. This is important to + * ensure that when systemctl is started via + * popen() or a similar call that expects to + * read EOF we actually do generate EOF and + * not delay this indefinitely by because we + * keep an unused copy of stdin around. */ + fd = open("/dev/tty", O_WRONLY); + if (fd < 0) { + log_error_errno(errno, "Failed to open /dev/tty: %m"); + _exit(EXIT_FAILURE); + } + + if (!stdout_is_tty) + dup2(fd, STDOUT_FILENO); + + if (!stderr_is_tty) + dup2(fd, STDERR_FILENO); + + if (fd > 2) + close(fd); + } + + /* Count arguments */ + va_start(ap, path); + for (n = 0; va_arg(ap, char*); n++) + ; + va_end(ap); + + /* Allocate strv */ + l = alloca(sizeof(char *) * (n + 1)); + + /* Fill in arguments */ + va_start(ap, path); + for (i = 0; i <= n; i++) + l[i] = va_arg(ap, char*); + va_end(ap); + + execv(path, l); + _exit(EXIT_FAILURE); +} + +bool in_initrd(void) { + static int saved = -1; + struct statfs s; + + if (saved >= 0) + return saved; + + /* We make two checks here: + * + * 1. the flag file /etc/initrd-release must exist + * 2. the root file system must be a memory file system + * + * The second check is extra paranoia, since misdetecting an + * initrd can have bad bad consequences due the initrd + * emptying when transititioning to the main systemd. + */ + + saved = access("/etc/initrd-release", F_OK) >= 0 && + statfs("/", &s) >= 0 && + is_temporary_fs(&s); + + return saved; +} + +/* hey glibc, APIs with callbacks without a user pointer are so useless */ +void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, + int (*compar) (const void *, const void *, void *), void *arg) { + size_t l, u, idx; + const void *p; + int comparison; + + l = 0; + u = nmemb; + while (l < u) { + idx = (l + u) / 2; + p = (void *)(((const char *) base) + (idx * size)); + comparison = compar(key, p, arg); + if (comparison < 0) + u = idx; + else if (comparison > 0) + l = idx + 1; + else + return (void *)p; + } + return NULL; +} + +int on_ac_power(void) { + bool found_offline = false, found_online = false; + _cleanup_closedir_ DIR *d = NULL; + + d = opendir("/sys/class/power_supply"); + if (!d) + return errno == ENOENT ? true : -errno; + + for (;;) { + struct dirent *de; + _cleanup_close_ int fd = -1, device = -1; + char contents[6]; + ssize_t n; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) + return -errno; + + if (!de) + break; + + if (hidden_file(de->d_name)) + continue; + + device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (device < 0) { + if (errno == ENOENT || errno == ENOTDIR) + continue; + + return -errno; + } + + fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) { + if (errno == ENOENT) + continue; + + return -errno; + } + + n = read(fd, contents, sizeof(contents)); + if (n < 0) + return -errno; + + if (n != 6 || memcmp(contents, "Mains\n", 6)) + continue; + + safe_close(fd); + fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) { + if (errno == ENOENT) + continue; + + return -errno; + } + + n = read(fd, contents, sizeof(contents)); + if (n < 0) + return -errno; + + if (n != 2 || contents[1] != '\n') + return -EIO; + + if (contents[0] == '1') { + found_online = true; + break; + } else if (contents[0] == '0') + found_offline = true; + else + return -EIO; + } + + return found_online || !found_offline; +} + +bool id128_is_valid(const char *s) { + size_t i, l; + + l = strlen(s); + if (l == 32) { + + /* Simple formatted 128bit hex string */ + + for (i = 0; i < l; i++) { + char c = s[i]; + + if (!(c >= '0' && c <= '9') && + !(c >= 'a' && c <= 'z') && + !(c >= 'A' && c <= 'Z')) + return false; + } + + } else if (l == 36) { + + /* Formatted UUID */ + + for (i = 0; i < l; i++) { + char c = s[i]; + + if ((i == 8 || i == 13 || i == 18 || i == 23)) { + if (c != '-') + return false; + } else { + if (!(c >= '0' && c <= '9') && + !(c >= 'a' && c <= 'z') && + !(c >= 'A' && c <= 'Z')) + return false; + } + } + + } else + return false; + + return true; +} + +int container_get_leader(const char *machine, pid_t *pid) { + _cleanup_free_ char *s = NULL, *class = NULL; + const char *p; + pid_t leader; + int r; + + assert(machine); + assert(pid); + + if (!machine_name_is_valid(machine)) + return -EINVAL; + + p = strjoina("/run/systemd/machines/", machine); + r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL); + if (r == -ENOENT) + return -EHOSTDOWN; + if (r < 0) + return r; + if (!s) + return -EIO; + + if (!streq_ptr(class, "container")) + return -EIO; + + r = parse_pid(s, &leader); + if (r < 0) + return r; + if (leader <= 1) + return -EIO; + + *pid = leader; + return 0; +} + +int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) { + _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1; + int rfd = -1; + + assert(pid >= 0); + + if (mntns_fd) { + const char *mntns; + + mntns = procfs_file_alloca(pid, "ns/mnt"); + mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (mntnsfd < 0) + return -errno; + } + + if (pidns_fd) { + const char *pidns; + + pidns = procfs_file_alloca(pid, "ns/pid"); + pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (pidnsfd < 0) + return -errno; + } + + if (netns_fd) { + const char *netns; + + netns = procfs_file_alloca(pid, "ns/net"); + netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (netnsfd < 0) + return -errno; + } + + if (userns_fd) { + const char *userns; + + userns = procfs_file_alloca(pid, "ns/user"); + usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (usernsfd < 0 && errno != ENOENT) + return -errno; + } + + if (root_fd) { + const char *root; + + root = procfs_file_alloca(pid, "root"); + rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY); + if (rfd < 0) + return -errno; + } + + if (pidns_fd) + *pidns_fd = pidnsfd; + + if (mntns_fd) + *mntns_fd = mntnsfd; + + if (netns_fd) + *netns_fd = netnsfd; + + if (userns_fd) + *userns_fd = usernsfd; + + if (root_fd) + *root_fd = rfd; + + pidnsfd = mntnsfd = netnsfd = usernsfd = -1; + + return 0; +} + +int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) { + if (userns_fd >= 0) { + /* Can't setns to your own userns, since then you could + * escalate from non-root to root in your own namespace, so + * check if namespaces equal before attempting to enter. */ + _cleanup_free_ char *userns_fd_path = NULL; + int r; + if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0) + return -ENOMEM; + + r = files_same(userns_fd_path, "/proc/self/ns/user"); + if (r < 0) + return r; + if (r) + userns_fd = -1; + } + + if (pidns_fd >= 0) + if (setns(pidns_fd, CLONE_NEWPID) < 0) + return -errno; + + if (mntns_fd >= 0) + if (setns(mntns_fd, CLONE_NEWNS) < 0) + return -errno; + + if (netns_fd >= 0) + if (setns(netns_fd, CLONE_NEWNET) < 0) + return -errno; + + if (userns_fd >= 0) + if (setns(userns_fd, CLONE_NEWUSER) < 0) + return -errno; + + if (root_fd >= 0) { + if (fchdir(root_fd) < 0) + return -errno; + + if (chroot(".") < 0) + return -errno; + } + + return reset_uid_gid(); +} + +uint64_t physical_memory(void) { + long mem; + + /* We return this as uint64_t in case we are running as 32bit + * process on a 64bit kernel with huge amounts of memory */ + + mem = sysconf(_SC_PHYS_PAGES); + assert(mem > 0); + + return (uint64_t) mem * (uint64_t) page_size(); +} + +int update_reboot_param_file(const char *param) { + int r = 0; + + if (param) { + r = write_string_file(REBOOT_PARAM_FILE, param, WRITE_STRING_FILE_CREATE); + if (r < 0) + return log_error_errno(r, "Failed to write reboot param to "REBOOT_PARAM_FILE": %m"); + } else + (void) unlink(REBOOT_PARAM_FILE); + + return 0; +} + +int version(void) { + puts(PACKAGE_STRING "\n" + SYSTEMD_FEATURES); + return 0; +} +#endif /* NM_IGNORED */ diff --git a/src/systemd/src/basic/util.h b/src/systemd/src/basic/util.h new file mode 100644 index 00000000..9393919d --- /dev/null +++ b/src/systemd/src/basic/util.h @@ -0,0 +1,186 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if 0 /* NM_IGNORED */ +#include "formats-util.h" +#endif /* NM_IGNORED */ +#include "macro.h" +#if 0 /* NM_IGNORED */ +#include "missing.h" +#endif /* NM_IGNORED */ +#include "time-util.h" + +size_t page_size(void) _pure_; +#define PAGE_ALIGN(l) ALIGN_TO((l), page_size()) + +static inline const char* yes_no(bool b) { + return b ? "yes" : "no"; +} + +static inline const char* true_false(bool b) { + return b ? "true" : "false"; +} + +static inline const char* one_zero(bool b) { + return b ? "1" : "0"; +} + +void execute_directories(const char* const* directories, usec_t timeout, char *argv[]); + +bool plymouth_running(void); + +bool display_is_local(const char *display) _pure_; +int socket_from_display(const char *display, char **path); + +int block_get_whole_disk(dev_t d, dev_t *ret); + +#define NULSTR_FOREACH(i, l) \ + for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1) + +#define NULSTR_FOREACH_PAIR(i, j, l) \ + for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i)) + +extern int saved_argc; +extern char **saved_argv; + +bool kexec_loaded(void); + +int prot_from_flags(int flags) _const_; + +int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...); + +bool in_initrd(void); + +void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, + int (*compar) (const void *, const void *, void *), + void *arg); + +/** + * Normal qsort requires base to be nonnull. Here were require + * that only if nmemb > 0. + */ +static inline void qsort_safe(void *base, size_t nmemb, size_t size, comparison_fn_t compar) { + if (nmemb <= 1) + return; + + assert(base); + qsort(base, nmemb, size, compar); +} + +int on_ac_power(void); + +#define memzero(x,l) (memset((x), 0, (l))) +#define zero(x) (memzero(&(x), sizeof(x))) + +static inline void *mempset(void *s, int c, size_t n) { + memset(s, c, n); + return (uint8_t*)s + n; +} + +static inline void _reset_errno_(int *saved_errno) { + errno = *saved_errno; +} + +#define PROTECT_ERRNO _cleanup_(_reset_errno_) __attribute__((unused)) int _saved_errno_ = errno + +static inline int negative_errno(void) { + /* This helper should be used to shut up gcc if you know 'errno' is + * negative. Instead of "return -errno;", use "return negative_errno();" + * It will suppress bogus gcc warnings in case it assumes 'errno' might + * be 0 and thus the caller's error-handling might not be triggered. */ + assert_return(errno > 0, -EINVAL); + return -errno; +} + +static inline unsigned u64log2(uint64_t n) { +#if __SIZEOF_LONG_LONG__ == 8 + return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0; +#else +#error "Wut?" +#endif +} + +static inline unsigned u32ctz(uint32_t n) { +#if __SIZEOF_INT__ == 4 + return __builtin_ctz(n); +#else +#error "Wut?" +#endif +} + +static inline unsigned log2i(int x) { + assert(x > 0); + + return __SIZEOF_INT__ * 8 - __builtin_clz(x) - 1; +} + +static inline unsigned log2u(unsigned x) { + assert(x > 0); + + return sizeof(unsigned) * 8 - __builtin_clz(x) - 1; +} + +static inline unsigned log2u_round_up(unsigned x) { + assert(x > 0); + + if (x == 1) + return 0; + + return log2u(x - 1) + 1; +} + +bool id128_is_valid(const char *s) _pure_; + +int container_get_leader(const char *machine, pid_t *pid); + +int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd); +int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd); + +uint64_t physical_memory(void); + +int update_reboot_param_file(const char *param); + +int version(void); diff --git a/src/systemd/src/libsystemd-network/arp-util.c b/src/systemd/src/libsystemd-network/arp-util.c new file mode 100644 index 00000000..0c898145 --- /dev/null +++ b/src/systemd/src/libsystemd-network/arp-util.c @@ -0,0 +1,156 @@ +/*** + This file is part of systemd. + + Copyright (C) 2014 Axis Communications AB. All rights reserved. + Copyright (C) 2015 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +#include "arp-util.h" +#include "fd-util.h" +#include "util.h" + +int arp_network_bind_raw_socket(int ifindex, be32_t address, const struct ether_addr *eth_mac) { + struct sock_filter filter[] = { + BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ + BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), /* packet >= arp packet ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hrd)), /* A <- header */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), /* header == ethernet ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pro)), /* A <- protocol */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), /* protocol == IP ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hln)), /* A <- hardware address length */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct ether_addr), 1, 0), /* length == sizeof(ether_addr)? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pln)), /* A <- protocol address length */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct in_addr), 1, 0), /* length == sizeof(in_addr) ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_op)), /* A <- operation */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0), /* protocol == request ? */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0), /* protocol == reply ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + /* Sender Hardware Address must be different from our own */ + BPF_STMT(BPF_LD + BPF_IMM, htobe32(*((uint32_t *) eth_mac))), /* A <- 4 bytes of client's MAC */ + BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_sha)), /* A <- 4 bytes of SHA */ + BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 6), /* A == 0 ? */ + BPF_STMT(BPF_LD + BPF_IMM, htobe16(*((uint16_t *) (((char *) eth_mac) + 4)))), /* A <- remainder of client's MAC */ + BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, arp_sha) + 4), /* A <- remainder of SHA */ + BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + /* Sender Protocol Address or Target Protocol Address must be equal to the one we care about*/ + BPF_STMT(BPF_LD + BPF_IMM, htobe32(address)), /* A <- clients IP */ + BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_spa)), /* A <- SPA */ + BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */ + BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */ + BPF_STMT(BPF_LD + BPF_IMM, htobe32(address)), /* A <- clients IP */ + BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_tpa)), /* A <- TPA */ + BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* X xor A */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 0, 1), /* A == 0 ? */ + BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + }; + struct sock_fprog fprog = { + .len = ELEMENTSOF(filter), + .filter = (struct sock_filter*) filter + }; + union sockaddr_union link = { + .ll.sll_family = AF_PACKET, + .ll.sll_protocol = htons(ETH_P_ARP), + .ll.sll_ifindex = ifindex, + .ll.sll_halen = ETH_ALEN, + .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + }; + _cleanup_close_ int s = -1; + int r; + + assert(ifindex > 0); + + s = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); + if (s < 0) + return -errno; + + r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); + if (r < 0) + return -errno; + + r = bind(s, &link.sa, sizeof(link.ll)); + if (r < 0) + return -errno; + + r = s; + s = -1; + + return r; +} + +static int arp_send_packet(int fd, int ifindex, + be32_t pa, const struct ether_addr *ha, + bool announce) { + union sockaddr_union link = { + .ll.sll_family = AF_PACKET, + .ll.sll_protocol = htons(ETH_P_ARP), + .ll.sll_ifindex = ifindex, + .ll.sll_halen = ETH_ALEN, + .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, + }; + struct ether_arp arp = { + .ea_hdr.ar_hrd = htons(ARPHRD_ETHER), /* HTYPE */ + .ea_hdr.ar_pro = htons(ETHERTYPE_IP), /* PTYPE */ + .ea_hdr.ar_hln = ETH_ALEN, /* HLEN */ + .ea_hdr.ar_pln = sizeof(be32_t), /* PLEN */ + .ea_hdr.ar_op = htons(ARPOP_REQUEST), /* REQUEST */ + }; + int r; + + assert(fd >= 0); + assert(pa != 0); + assert(ha); + + memcpy(&arp.arp_sha, ha, ETH_ALEN); + memcpy(&arp.arp_tpa, &pa, sizeof(pa)); + + if (announce) + memcpy(&arp.arp_spa, &pa, sizeof(pa)); + + r = sendto(fd, &arp, sizeof(struct ether_arp), 0, &link.sa, sizeof(link.ll)); + if (r < 0) + return -errno; + + return 0; +} + +int arp_send_probe(int fd, int ifindex, + be32_t pa, const struct ether_addr *ha) { + return arp_send_packet(fd, ifindex, pa, ha, false); +} + +int arp_send_announcement(int fd, int ifindex, + be32_t pa, const struct ether_addr *ha) { + return arp_send_packet(fd, ifindex, pa, ha, true); +} diff --git a/src/systemd/src/libsystemd-network/arp-util.h b/src/systemd/src/libsystemd-network/arp-util.h new file mode 100644 index 00000000..16af8962 --- /dev/null +++ b/src/systemd/src/libsystemd-network/arp-util.h @@ -0,0 +1,36 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2014 Axis Communications AB. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include + +#include "socket-util.h" +#include "sparse-endian.h" + +int arp_network_bind_raw_socket(int index, be32_t address, const struct ether_addr *eth_mac); + +int arp_send_probe(int fd, int ifindex, + be32_t pa, const struct ether_addr *ha); +int arp_send_announcement(int fd, int ifindex, + be32_t pa, const struct ether_addr *ha); diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.c b/src/systemd/src/libsystemd-network/dhcp-identifier.c new file mode 100644 index 00000000..732199de --- /dev/null +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.c @@ -0,0 +1,116 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2015 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#if 0 /* NM_IGNORED */ +#include "libudev.h" +#endif /* NM_IGNORED */ +#include "sd-id128.h" + +#include "dhcp-identifier.h" +#include "dhcp6-protocol.h" +#include "network-internal.h" +#include "siphash24.h" +#include "sparse-endian.h" +#if 0 /* NM_IGNORED */ +#include "udev-util.h" +#include "virt.h" +#else /* NM_IGNORED */ +#include +#endif /* NM_IGNORED */ + +#define SYSTEMD_PEN 43793 +#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09) + +int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len) { + sd_id128_t machine_id; + uint64_t hash; + int r; + + assert(duid); + assert(len); + + r = sd_id128_get_machine(&machine_id); + if (r < 0) + return r; + + unaligned_write_be16(&duid->type, DHCP6_DUID_EN); + unaligned_write_be32(&duid->en.pen, SYSTEMD_PEN); + + *len = sizeof(duid->type) + sizeof(duid->en); + + /* a bit of snake-oil perhaps, but no need to expose the machine-id + directly; duid->en.id might not be aligned, so we need to copy */ + hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes)); + memcpy(duid->en.id, &hash, sizeof(duid->en.id)); + + return 0; +} + +int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id) { +#if 0 /* NM_IGNORED */ + /* name is a pointer to memory in the udev_device struct, so must + have the same scope */ + _cleanup_udev_device_unref_ struct udev_device *device = NULL; +#else /* NM_IGNORED */ + char name_buf[IF_NAMESIZE]; +#endif /* NM_IGNORED */ + const char *name = NULL; + uint64_t id; + +#if 0 /* NM_IGNORED */ + if (detect_container() <= 0) { + /* not in a container, udev will be around */ + _cleanup_udev_unref_ struct udev *udev; + char ifindex_str[2 + DECIMAL_STR_MAX(int)]; + + udev = udev_new(); + if (!udev) + return -ENOMEM; + + sprintf(ifindex_str, "n%d", ifindex); + device = udev_device_new_from_device_id(udev, ifindex_str); + if (device) { + if (udev_device_get_is_initialized(device) <= 0) + /* not yet ready */ + return -EBUSY; + + name = net_get_name(device); + } + } +#else /* NM_IGNORED */ + name = if_indextoname(ifindex, name_buf); +#endif /* NM_IGNORED */ + + if (name) + id = siphash24(name, strlen(name), HASH_KEY.bytes); + else + /* fall back to MAC address if no predictable name available */ + id = siphash24(mac, mac_len, HASH_KEY.bytes); + + id = htole64(id); + + /* fold into 32 bits */ + unaligned_write_be32(_id, (id & 0xffffffff) ^ (id >> 32)); + + return 0; +} diff --git a/src/systemd/src/libsystemd-network/dhcp-identifier.h b/src/systemd/src/libsystemd-network/dhcp-identifier.h new file mode 100644 index 00000000..106dba39 --- /dev/null +++ b/src/systemd/src/libsystemd-network/dhcp-identifier.h @@ -0,0 +1,67 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2015 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include "sd-id128.h" + +#include "macro.h" +#include "sparse-endian.h" +#include "unaligned.h" + +/* RFC 3315 section 9.1: + * A DUID can be no more than 128 octets long (not including the type code). + */ +#define MAX_DUID_LEN 128 + +struct duid { + uint16_t type; + union { + struct { + /* DHCP6_DUID_LLT */ + uint16_t htype; + uint32_t time; + uint8_t haddr[0]; + } _packed_ llt; + struct { + /* DHCP6_DUID_EN */ + uint32_t pen; + uint8_t id[8]; + } _packed_ en; + struct { + /* DHCP6_DUID_LL */ + int16_t htype; + uint8_t haddr[0]; + } _packed_ ll; + struct { + /* DHCP6_DUID_UUID */ + sd_id128_t uuid; + } _packed_ uuid; + struct { + uint8_t data[MAX_DUID_LEN]; + } _packed_ raw; + }; +} _packed_; + +int dhcp_identifier_set_duid_en(struct duid *duid, size_t *len); +int dhcp_identifier_set_iaid(int ifindex, uint8_t *mac, size_t mac_len, void *_id); diff --git a/src/systemd/src/libsystemd-network/dhcp-internal.h b/src/systemd/src/libsystemd-network/dhcp-internal.h new file mode 100644 index 00000000..09dcf7e9 --- /dev/null +++ b/src/systemd/src/libsystemd-network/dhcp-internal.h @@ -0,0 +1,72 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + Copyright (C) 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "sd-dhcp-client.h" + +#include "dhcp-protocol.h" +#include "socket-util.h" + +int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link, + uint32_t xid, const uint8_t *mac_addr, + size_t mac_addr_len, uint16_t arp_type); +int dhcp_network_bind_udp_socket(be32_t address, uint16_t port); +int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, + const void *packet, size_t len); +int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, + const void *packet, size_t len); + +int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_t overload, + uint8_t code, size_t optlen, const void *optval); + +typedef int (*dhcp_option_cb_t)(uint8_t code, uint8_t len, + const void *option, void *userdata); + +int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **error_message); + +int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, + uint8_t type, uint16_t arp_type, size_t optlen, + size_t *optoffset); + +uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len); + +void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr, + uint16_t source, be32_t destination_addr, + uint16_t destination, uint16_t len); + +int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum); + +/* If we are invoking callbacks of a dhcp-client, ensure unreffing the + * client from the callback doesn't destroy the object we are working + * on */ +#define DHCP_CLIENT_DONT_DESTROY(client) \ + _cleanup_(sd_dhcp_client_unrefp) _unused_ sd_dhcp_client *_dont_destroy_##client = sd_dhcp_client_ref(client) + +#define log_dhcp_client(client, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__) diff --git a/src/systemd/src/libsystemd-network/dhcp-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h new file mode 100644 index 00000000..8ce52a7d --- /dev/null +++ b/src/systemd/src/libsystemd-network/dhcp-lease-internal.h @@ -0,0 +1,106 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + Copyright (C) 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +#include "sd-dhcp-client.h" + +#include "dhcp-protocol.h" +#include "list.h" +#include "util.h" + +struct sd_dhcp_route { + struct in_addr dst_addr; + struct in_addr gw_addr; + unsigned char dst_prefixlen; +}; + +struct sd_dhcp_raw_option { + LIST_FIELDS(struct sd_dhcp_raw_option, options); + + uint8_t tag; + uint8_t length; + void *data; +}; + +struct sd_dhcp_lease { + unsigned n_ref; + + /* each 0 if unset */ + uint32_t t1; + uint32_t t2; + uint32_t lifetime; + + /* each 0 if unset */ + be32_t address; + be32_t server_address; + be32_t router; + be32_t next_server; + + bool have_subnet_mask; + be32_t subnet_mask; + + bool have_broadcast; + be32_t broadcast; + + struct in_addr *dns; + size_t dns_size; + + struct in_addr *ntp; + size_t ntp_size; + + struct sd_dhcp_route *static_route; + size_t static_route_size, static_route_allocated; + + uint16_t mtu; /* 0 if unset */ + + char *domainname; + char *hostname; + char *root_path; + + void *client_id; + size_t client_id_len; + + void *vendor_specific; + size_t vendor_specific_len; + + char *timezone; + + LIST_HEAD(struct sd_dhcp_raw_option, private_options); +}; + +int dhcp_lease_new(sd_dhcp_lease **ret); + +int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata); +int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len); + +int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease); + +int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len); + +int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file); +int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file); diff --git a/src/systemd/src/libsystemd-network/dhcp-network.c b/src/systemd/src/libsystemd-network/dhcp-network.c new file mode 100644 index 00000000..15a0bb7b --- /dev/null +++ b/src/systemd/src/libsystemd-network/dhcp-network.c @@ -0,0 +1,237 @@ +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dhcp-internal.h" +#include "fd-util.h" +#include "socket-util.h" + +static int _bind_raw_socket(int ifindex, union sockaddr_union *link, + uint32_t xid, const uint8_t *mac_addr, + size_t mac_addr_len, + const uint8_t *bcast_addr, + const struct ether_addr *eth_mac, + uint16_t arp_type, uint8_t dhcp_hlen) { + struct sock_filter filter[] = { + BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ + BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(DHCPPacket), 1, 0), /* packet >= DHCPPacket ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, ip.protocol)), /* A <- IP protocol */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0), /* IP protocol == UDP ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, ip.frag_off)), /* A <- Flags */ + BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x20), /* A <- A & 0x20 (More Fragments bit) */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, ip.frag_off)), /* A <- Flags + Fragment offset */ + BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x1fff), /* A <- A & 0x1fff (Fragment offset) */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, udp.dest)), /* A <- UDP destination port */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_PORT_CLIENT, 1, 0), /* UDP destination port == DHCP client port ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.op)), /* A <- DHCP op */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTREPLY, 1, 0), /* op == BOOTREPLY ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.htype)), /* A <- DHCP header type */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arp_type, 1, 0), /* header type == arp_type ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- MAC address length */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0), /* address length == dhcp_hlen ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)), /* A <- client identifier */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0), /* client identifier == xid ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_IMM, htobe32(*((unsigned int *) eth_mac))), /* A <- 4 bytes of client's MAC */ + BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */ + BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_IMM, htobe16(*((unsigned short *) (((char *) eth_mac) + 4)))), /* A <- remainder of client's MAC */ + BPF_STMT(BPF_MISC + BPF_TAX, 0), /* X <- A */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4), /* A <- remainder of MAC from dhcp.chaddr */ + BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0), /* A xor X */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)), /* A <- DHCP magic cookie */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0), /* cookie == DHCP magic cookie ? */ + BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ + BPF_STMT(BPF_RET + BPF_K, 65535), /* return all */ + }; + struct sock_fprog fprog = { + .len = ELEMENTSOF(filter), + .filter = filter + }; + _cleanup_close_ int s = -1; + int r, on = 1; + + assert(ifindex > 0); + assert(link); + + s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); + if (s < 0) + return -errno; + + r = setsockopt(s, SOL_PACKET, PACKET_AUXDATA, &on, sizeof(on)); + if (r < 0) + return -errno; + + r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); + if (r < 0) + return -errno; + + link->ll.sll_family = AF_PACKET; + link->ll.sll_protocol = htons(ETH_P_IP); + link->ll.sll_ifindex = ifindex; + link->ll.sll_hatype = htons(arp_type); + link->ll.sll_halen = mac_addr_len; + memcpy(link->ll.sll_addr, bcast_addr, mac_addr_len); + + r = bind(s, &link->sa, sizeof(link->ll)); + if (r < 0) + return -errno; + + r = s; + s = -1; + + return r; +} + +int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, + uint32_t xid, const uint8_t *mac_addr, + size_t mac_addr_len, uint16_t arp_type) { + static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + /* Default broadcast address for IPoIB */ + static const uint8_t ib_bcast[] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff + }; + struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } }; + const uint8_t *bcast_addr = NULL; + uint8_t dhcp_hlen = 0; + + assert_return(mac_addr_len > 0, -EINVAL); + + if (arp_type == ARPHRD_ETHER) { + assert_return(mac_addr_len == ETH_ALEN, -EINVAL); + memcpy(ð_mac, mac_addr, ETH_ALEN); + bcast_addr = eth_bcast; + dhcp_hlen = ETH_ALEN; + } else if (arp_type == ARPHRD_INFINIBAND) { + assert_return(mac_addr_len == INFINIBAND_ALEN, -EINVAL); + bcast_addr = ib_bcast; + } else + return -EINVAL; + + return _bind_raw_socket(ifindex, link, xid, mac_addr, mac_addr_len, + bcast_addr, ð_mac, arp_type, dhcp_hlen); +} + +int dhcp_network_bind_udp_socket(be32_t address, uint16_t port) { + union sockaddr_union src = { + .in.sin_family = AF_INET, + .in.sin_port = htobe16(port), + .in.sin_addr.s_addr = address, + }; + _cleanup_close_ int s = -1; + int r, on = 1, tos = IPTOS_CLASS_CS6; + + s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); + if (s < 0) + return -errno; + + r = setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); + if (r < 0) + return -errno; + + r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (r < 0) + return -errno; + + if (address == INADDR_ANY) { + r = setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)); + if (r < 0) + return -errno; + + r = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)); + if (r < 0) + return -errno; + } else { + r = setsockopt(s, IPPROTO_IP, IP_FREEBIND, &on, sizeof(on)); + if (r < 0) + return -errno; + } + + r = bind(s, &src.sa, sizeof(src.in)); + if (r < 0) + return -errno; + + r = s; + s = -1; + + return r; +} + +int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, + const void *packet, size_t len) { + int r; + + assert(link); + assert(packet); + assert(len); + + r = sendto(s, packet, len, 0, &link->sa, sizeof(link->ll)); + if (r < 0) + return -errno; + + return 0; +} + +int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, + const void *packet, size_t len) { + union sockaddr_union dest = { + .in.sin_family = AF_INET, + .in.sin_port = htobe16(port), + .in.sin_addr.s_addr = address, + }; + int r; + + assert(s >= 0); + assert(packet); + assert(len); + + r = sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in)); + if (r < 0) + return -errno; + + return 0; +} diff --git a/src/systemd/src/libsystemd-network/dhcp-option.c b/src/systemd/src/libsystemd-network/dhcp-option.c new file mode 100644 index 00000000..8c359a48 --- /dev/null +++ b/src/systemd/src/libsystemd-network/dhcp-option.c @@ -0,0 +1,272 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "alloc-util.h" +#include "utf8.h" + +#include "dhcp-internal.h" + +static int option_append(uint8_t options[], size_t size, size_t *offset, + uint8_t code, size_t optlen, const void *optval) { + assert(options); + assert(offset); + + if (code != DHCP_OPTION_END) + /* always make sure there is space for an END option */ + size --; + + switch (code) { + + case DHCP_OPTION_PAD: + case DHCP_OPTION_END: + if (size < *offset + 1) + return -ENOBUFS; + + options[*offset] = code; + *offset += 1; + break; + + default: + if (size < *offset + optlen + 2) + return -ENOBUFS; + + options[*offset] = code; + options[*offset + 1] = optlen; + + if (optlen) { + assert(optval); + + memcpy(&options[*offset + 2], optval, optlen); + } + + *offset += optlen + 2; + + break; + } + + return 0; +} + +int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, + uint8_t overload, + uint8_t code, size_t optlen, const void *optval) { + size_t file_offset = 0, sname_offset =0; + bool file, sname; + int r; + + assert(message); + assert(offset); + + file = overload & DHCP_OVERLOAD_FILE; + sname = overload & DHCP_OVERLOAD_SNAME; + + if (*offset < size) { + /* still space in the options array */ + r = option_append(message->options, size, offset, code, optlen, optval); + if (r >= 0) + return 0; + else if (r == -ENOBUFS && (file || sname)) { + /* did not fit, but we have more buffers to try + close the options array and move the offset to its end */ + r = option_append(message->options, size, offset, DHCP_OPTION_END, 0, NULL); + if (r < 0) + return r; + + *offset = size; + } else + return r; + } + + if (overload & DHCP_OVERLOAD_FILE) { + file_offset = *offset - size; + + if (file_offset < sizeof(message->file)) { + /* still space in the 'file' array */ + r = option_append(message->file, sizeof(message->file), &file_offset, code, optlen, optval); + if (r >= 0) { + *offset = size + file_offset; + return 0; + } else if (r == -ENOBUFS && sname) { + /* did not fit, but we have more buffers to try + close the file array and move the offset to its end */ + r = option_append(message->options, size, offset, DHCP_OPTION_END, 0, NULL); + if (r < 0) + return r; + + *offset = size + sizeof(message->file); + } else + return r; + } + } + + if (overload & DHCP_OVERLOAD_SNAME) { + sname_offset = *offset - size - (file ? sizeof(message->file) : 0); + + if (sname_offset < sizeof(message->sname)) { + /* still space in the 'sname' array */ + r = option_append(message->sname, sizeof(message->sname), &sname_offset, code, optlen, optval); + if (r >= 0) { + *offset = size + (file ? sizeof(message->file) : 0) + sname_offset; + return 0; + } else { + /* no space, or other error, give up */ + return r; + } + } + } + + return -ENOBUFS; +} + +static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload, + uint8_t *message_type, char **error_message, dhcp_option_cb_t cb, + void *userdata) { + uint8_t code, len; + const uint8_t *option; + size_t offset = 0; + + while (offset < buflen) { + code = options[offset ++]; + + switch (code) { + case DHCP_OPTION_PAD: + continue; + + case DHCP_OPTION_END: + return 0; + } + + if (buflen < offset + 1) + return -ENOBUFS; + + len = options[offset ++]; + + if (buflen < offset + len) + return -EINVAL; + + option = &options[offset]; + + switch (code) { + case DHCP_OPTION_MESSAGE_TYPE: + if (len != 1) + return -EINVAL; + + if (message_type) + *message_type = *option; + + break; + + case DHCP_OPTION_ERROR_MESSAGE: + if (len == 0) + return -EINVAL; + + if (error_message) { + _cleanup_free_ char *string = NULL; + + /* Accept a trailing NUL byte */ + if (memchr(option, 0, len - 1)) + return -EINVAL; + + string = strndup((const char *) option, len); + if (!string) + return -ENOMEM; + + if (!ascii_is_valid(string)) + return -EINVAL; + + free(*error_message); + *error_message = string; + string = NULL; + } + + break; + case DHCP_OPTION_OVERLOAD: + if (len != 1) + return -EINVAL; + + if (overload) + *overload = *option; + + break; + + default: + if (cb) + cb(code, len, option, userdata); + + break; + } + + offset += len; + } + + if (offset < buflen) + return -EINVAL; + + return 0; +} + +int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_cb_t cb, void *userdata, char **_error_message) { + _cleanup_free_ char *error_message = NULL; + uint8_t overload = 0; + uint8_t message_type = 0; + int r; + + if (!message) + return -EINVAL; + + if (len < sizeof(DHCPMessage)) + return -EINVAL; + + len -= sizeof(DHCPMessage); + + r = parse_options(message->options, len, &overload, &message_type, &error_message, cb, userdata); + if (r < 0) + return r; + + if (overload & DHCP_OVERLOAD_FILE) { + r = parse_options(message->file, sizeof(message->file), NULL, &message_type, &error_message, cb, userdata); + if (r < 0) + return r; + } + + if (overload & DHCP_OVERLOAD_SNAME) { + r = parse_options(message->sname, sizeof(message->sname), NULL, &message_type, &error_message, cb, userdata); + if (r < 0) + return r; + } + + if (message_type == 0) + return -ENOMSG; + + if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE)) { + *_error_message = error_message; + error_message = NULL; + } + + return message_type; +} diff --git a/src/systemd/src/libsystemd-network/dhcp-packet.c b/src/systemd/src/libsystemd-network/dhcp-packet.c new file mode 100644 index 00000000..88a2161d --- /dev/null +++ b/src/systemd/src/libsystemd-network/dhcp-packet.c @@ -0,0 +1,193 @@ +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + Copyright (C) 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "dhcp-internal.h" +#include "dhcp-protocol.h" + +#define DHCP_CLIENT_MIN_OPTIONS_SIZE 312 + +int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, + uint8_t type, uint16_t arp_type, size_t optlen, + size_t *optoffset) { + size_t offset = 0; + int r; + + assert(op == BOOTREQUEST || op == BOOTREPLY); + assert(arp_type == ARPHRD_ETHER || arp_type == ARPHRD_INFINIBAND); + + message->op = op; + message->htype = arp_type; + message->hlen = (arp_type == ARPHRD_ETHER) ? ETHER_ADDR_LEN : 0; + message->xid = htobe32(xid); + message->magic = htobe32(DHCP_MAGIC_COOKIE); + + r = dhcp_option_append(message, optlen, &offset, 0, + DHCP_OPTION_MESSAGE_TYPE, 1, &type); + if (r < 0) + return r; + + *optoffset = offset; + + return 0; +} + +uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) { + uint64_t *buf_64 = (uint64_t*)buf; + uint64_t *end_64 = buf_64 + (len / sizeof(uint64_t)); + uint64_t sum = 0; + + /* See RFC1071 */ + + while (buf_64 < end_64) { + sum += *buf_64; + if (sum < *buf_64) + /* wrap around in one's complement */ + sum++; + + buf_64 ++; + } + + if (len % sizeof(uint64_t)) { + /* If the buffer is not aligned to 64-bit, we need + to zero-pad the last few bytes and add them in */ + uint64_t buf_tail = 0; + + memcpy(&buf_tail, buf_64, len % sizeof(uint64_t)); + + sum += buf_tail; + if (sum < buf_tail) + /* wrap around */ + sum++; + } + + while (sum >> 16) + sum = (sum & 0xffff) + (sum >> 16); + + return ~sum; +} + +void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr, + uint16_t source_port, be32_t destination_addr, + uint16_t destination_port, uint16_t len) { + packet->ip.version = IPVERSION; + packet->ip.ihl = DHCP_IP_SIZE / 4; + packet->ip.tot_len = htobe16(len); + + packet->ip.tos = IPTOS_CLASS_CS6; + + packet->ip.protocol = IPPROTO_UDP; + packet->ip.saddr = source_addr; + packet->ip.daddr = destination_addr; + + packet->udp.source = htobe16(source_port); + packet->udp.dest = htobe16(destination_port); + + packet->udp.len = htobe16(len - DHCP_IP_SIZE); + + packet->ip.check = packet->udp.len; + packet->udp.check = dhcp_packet_checksum((uint8_t*)&packet->ip.ttl, len - 8); + + packet->ip.ttl = IPDEFTTL; + packet->ip.check = 0; + packet->ip.check = dhcp_packet_checksum((uint8_t*)&packet->ip, DHCP_IP_SIZE); +} + +int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum) { + size_t hdrlen; + + assert(packet); + + /* IP */ + + if (packet->ip.version != IPVERSION) { + log_debug("ignoring packet: not IPv4"); + return -EINVAL; + } + + if (packet->ip.ihl < 5) { + log_debug("ignoring packet: IPv4 IHL (%u words) invalid", + packet->ip.ihl); + return -EINVAL; + } + + hdrlen = packet->ip.ihl * 4; + if (hdrlen < 20) { + log_debug("ignoring packet: IPv4 IHL (%zu bytes) " + "smaller than minimum (20 bytes)", hdrlen); + return -EINVAL; + } + + if (len < hdrlen) { + log_debug("ignoring packet: packet (%zu bytes) " + "smaller than expected (%zu) by IP header", len, + hdrlen); + return -EINVAL; + } + + /* UDP */ + + if (packet->ip.protocol != IPPROTO_UDP) { + log_debug("ignoring packet: not UDP"); + return -EINVAL; + } + + if (len < hdrlen + be16toh(packet->udp.len)) { + log_debug("ignoring packet: packet (%zu bytes) " + "smaller than expected (%zu) by UDP header", len, + hdrlen + be16toh(packet->udp.len)); + return -EINVAL; + } + + if (be16toh(packet->udp.dest) != DHCP_PORT_CLIENT) { + log_debug("ignoring packet: to port %u, which " + "is not the DHCP client port (%u)", + be16toh(packet->udp.dest), DHCP_PORT_CLIENT); + return -EINVAL; + } + + /* checksums - computing these is relatively expensive, so only do it + if all the other checks have passed + */ + + if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen)) { + log_debug("ignoring packet: invalid IP checksum"); + return -EINVAL; + } + + if (checksum && packet->udp.check) { + packet->ip.check = packet->udp.len; + packet->ip.ttl = 0; + + if (dhcp_packet_checksum((uint8_t*)&packet->ip.ttl, + be16toh(packet->udp.len) + 12)) { + log_debug("ignoring packet: invalid UDP checksum"); + return -EINVAL; + } + } + + return 0; +} diff --git a/src/systemd/src/libsystemd-network/dhcp-protocol.h b/src/systemd/src/libsystemd-network/dhcp-protocol.h new file mode 100644 index 00000000..0d80a916 --- /dev/null +++ b/src/systemd/src/libsystemd-network/dhcp-protocol.h @@ -0,0 +1,159 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include + +#include "macro.h" +#include "sparse-endian.h" + +struct DHCPMessage { + uint8_t op; + uint8_t htype; + uint8_t hlen; + uint8_t hops; + be32_t xid; + be16_t secs; + be16_t flags; + be32_t ciaddr; + be32_t yiaddr; + be32_t siaddr; + be32_t giaddr; + uint8_t chaddr[16]; + uint8_t sname[64]; + uint8_t file[128]; + be32_t magic; + uint8_t options[0]; +} _packed_; + +typedef struct DHCPMessage DHCPMessage; + +struct DHCPPacket { + struct iphdr ip; + struct udphdr udp; + DHCPMessage dhcp; +} _packed_; + +typedef struct DHCPPacket DHCPPacket; + +#define DHCP_IP_SIZE (int32_t)(sizeof(struct iphdr)) +#define DHCP_IP_UDP_SIZE (int32_t)(sizeof(struct udphdr) + DHCP_IP_SIZE) +#define DHCP_MESSAGE_SIZE (int32_t)(sizeof(DHCPMessage)) +#define DHCP_DEFAULT_MIN_SIZE 576 /* the minimum internet hosts must be able to receive */ +#define DHCP_MIN_OPTIONS_SIZE DHCP_DEFAULT_MIN_SIZE - DHCP_IP_UDP_SIZE - DHCP_MESSAGE_SIZE +#define DHCP_MAGIC_COOKIE (uint32_t)(0x63825363) + +enum { + DHCP_PORT_SERVER = 67, + DHCP_PORT_CLIENT = 68, +}; + +enum DHCPState { + DHCP_STATE_INIT = 0, + DHCP_STATE_SELECTING = 1, + DHCP_STATE_INIT_REBOOT = 2, + DHCP_STATE_REBOOTING = 3, + DHCP_STATE_REQUESTING = 4, + DHCP_STATE_BOUND = 5, + DHCP_STATE_RENEWING = 6, + DHCP_STATE_REBINDING = 7, + DHCP_STATE_STOPPED = 8, +}; + +typedef enum DHCPState DHCPState; + +enum { + BOOTREQUEST = 1, + BOOTREPLY = 2, +}; + +enum { + DHCP_DISCOVER = 1, + DHCP_OFFER = 2, + DHCP_REQUEST = 3, + DHCP_DECLINE = 4, + DHCP_ACK = 5, + DHCP_NAK = 6, + DHCP_RELEASE = 7, + DHCP_INFORM = 8, + DHCP_FORCERENEW = 9, +}; + +enum { + DHCP_OVERLOAD_FILE = 1, + DHCP_OVERLOAD_SNAME = 2, +}; + +enum { + DHCP_OPTION_PAD = 0, + DHCP_OPTION_SUBNET_MASK = 1, + DHCP_OPTION_TIME_OFFSET = 2, + DHCP_OPTION_ROUTER = 3, + DHCP_OPTION_DOMAIN_NAME_SERVER = 6, + DHCP_OPTION_HOST_NAME = 12, + DHCP_OPTION_BOOT_FILE_SIZE = 13, + DHCP_OPTION_DOMAIN_NAME = 15, + DHCP_OPTION_ROOT_PATH = 17, + DHCP_OPTION_ENABLE_IP_FORWARDING = 19, + DHCP_OPTION_ENABLE_IP_FORWARDING_NL = 20, + DHCP_OPTION_POLICY_FILTER = 21, + DHCP_OPTION_INTERFACE_MDR = 22, + DHCP_OPTION_INTERFACE_TTL = 23, + DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT = 24, + DHCP_OPTION_INTERFACE_MTU = 26, + DHCP_OPTION_BROADCAST = 28, + DHCP_OPTION_STATIC_ROUTE = 33, + DHCP_OPTION_NTP_SERVER = 42, + DHCP_OPTION_VENDOR_SPECIFIC = 43, + DHCP_OPTION_REQUESTED_IP_ADDRESS = 50, + DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51, + DHCP_OPTION_OVERLOAD = 52, + DHCP_OPTION_MESSAGE_TYPE = 53, + DHCP_OPTION_SERVER_IDENTIFIER = 54, + DHCP_OPTION_PARAMETER_REQUEST_LIST = 55, + DHCP_OPTION_ERROR_MESSAGE = 56, + DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57, + DHCP_OPTION_RENEWAL_T1_TIME = 58, + DHCP_OPTION_REBINDING_T2_TIME = 59, + DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, + DHCP_OPTION_CLIENT_IDENTIFIER = 61, + DHCP_OPTION_FQDN = 81, + DHCP_OPTION_NEW_POSIX_TIMEZONE = 100, + DHCP_OPTION_NEW_TZDB_TIMEZONE = 101, + DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, + DHCP_OPTION_PRIVATE_BASE = 224, + DHCP_OPTION_PRIVATE_LAST = 254, + DHCP_OPTION_END = 255, +}; + +#define DHCP_MAX_FQDN_LENGTH 255 + +enum { + DHCP_FQDN_FLAG_S = (1 << 0), + DHCP_FQDN_FLAG_O = (1 << 1), + DHCP_FQDN_FLAG_E = (1 << 2), + DHCP_FQDN_FLAG_N = (1 << 3), +}; diff --git a/src/systemd/src/libsystemd-network/dhcp6-internal.h b/src/systemd/src/libsystemd-network/dhcp6-internal.h new file mode 100644 index 00000000..09cff3c4 --- /dev/null +++ b/src/systemd/src/libsystemd-network/dhcp6-internal.h @@ -0,0 +1,84 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +#include "sd-event.h" + +#include "list.h" +#include "macro.h" +#include "sparse-endian.h" + +typedef struct DHCP6Address DHCP6Address; + +struct DHCP6Address { + LIST_FIELDS(DHCP6Address, addresses); + + struct { + struct in6_addr address; + be32_t lifetime_preferred; + be32_t lifetime_valid; + } iaaddr _packed_; +}; + +struct DHCP6IA { + uint16_t type; + struct { + be32_t id; + be32_t lifetime_t1; + be32_t lifetime_t2; + } _packed_; + sd_event_source *timeout_t1; + sd_event_source *timeout_t2; + + LIST_HEAD(DHCP6Address, addresses); +}; + +typedef struct DHCP6IA DHCP6IA; + +#define log_dhcp6_client(p, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCPv6 CLIENT: " fmt, ##__VA_ARGS__) + +int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, + size_t optlen, const void *optval); +int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia); +int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, + size_t *optlen, uint8_t **optvalue); +int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, + DHCP6IA *ia); +int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen, + struct in6_addr **addrs, size_t count, + size_t *allocated); +int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, + char ***str_arr); + +int dhcp6_network_bind_udp_socket(int index, struct in6_addr *address); +int dhcp6_network_send_udp_socket(int s, struct in6_addr *address, + const void *packet, size_t len); + +const char *dhcp6_message_type_to_string(int s) _const_; +int dhcp6_message_type_from_string(const char *s) _pure_; +const char *dhcp6_message_status_to_string(int s) _const_; +int dhcp6_message_status_from_string(const char *s) _pure_; diff --git a/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h new file mode 100644 index 00000000..6b51658c --- /dev/null +++ b/src/systemd/src/libsystemd-network/dhcp6-lease-internal.h @@ -0,0 +1,78 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include + +#include "sd-dhcp6-lease.h" + +#include "dhcp6-internal.h" + +struct sd_dhcp6_lease { + unsigned n_ref; + + uint8_t *serverid; + size_t serverid_len; + uint8_t preference; + bool rapid_commit; + + DHCP6IA ia; + + DHCP6Address *addr_iter; + + struct in6_addr *dns; + size_t dns_count; + size_t dns_allocated; + char **domains; + size_t domains_count; + struct in6_addr *ntp; + size_t ntp_count; + size_t ntp_allocated; + char **ntp_fqdn; + size_t ntp_fqdn_count; +}; + +int dhcp6_lease_clear_timers(DHCP6IA *ia); +int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire); +DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia); + +int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id, + size_t len); +int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len); +int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference); +int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference); +int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease); +int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit); + +int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid); + +int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen); +int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval, + size_t optlen); +int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen); +int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, + size_t optlen) ; + +int dhcp6_lease_new(sd_dhcp6_lease **ret); diff --git a/src/systemd/src/libsystemd-network/dhcp6-network.c b/src/systemd/src/libsystemd-network/dhcp6-network.c new file mode 100644 index 00000000..e4883019 --- /dev/null +++ b/src/systemd/src/libsystemd-network/dhcp6-network.c @@ -0,0 +1,93 @@ +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dhcp6-internal.h" +#include "dhcp6-protocol.h" +#include "fd-util.h" +#include "socket-util.h" + +int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) { + union sockaddr_union src = { + .in6.sin6_family = AF_INET6, + .in6.sin6_port = htobe16(DHCP6_PORT_CLIENT), + .in6.sin6_scope_id = index, + }; + _cleanup_close_ int s = -1; + int r, off = 0, on = 1; + + assert(index > 0); + assert(local_address); + + src.in6.sin6_addr = *local_address; + + s = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_UDP); + if (s < 0) + return -errno; + + r = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); + if (r < 0) + return -errno; + + r = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, sizeof(off)); + if (r < 0) + return -errno; + + r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); + if (r < 0) + return -errno; + + r = bind(s, &src.sa, sizeof(src.in6)); + if (r < 0) + return -errno; + + r = s; + s = -1; + return r; +} + +int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address, + const void *packet, size_t len) { + union sockaddr_union dest = { + .in6.sin6_family = AF_INET6, + .in6.sin6_port = htobe16(DHCP6_PORT_SERVER), + }; + int r; + + assert(server_address); + + memcpy(&dest.in6.sin6_addr, server_address, sizeof(dest.in6.sin6_addr)); + + r = sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in6)); + if (r < 0) + return -errno; + + return 0; +} diff --git a/src/systemd/src/libsystemd-network/dhcp6-option.c b/src/systemd/src/libsystemd-network/dhcp6-option.c new file mode 100644 index 00000000..0d61eddb --- /dev/null +++ b/src/systemd/src/libsystemd-network/dhcp6-option.c @@ -0,0 +1,416 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include + +#include "alloc-util.h" +#include "dhcp6-internal.h" +#include "dhcp6-protocol.h" +#include "dns-domain.h" +#include "sparse-endian.h" +#include "strv.h" +#include "unaligned.h" +#include "util.h" + +#define DHCP6_OPTION_IA_NA_LEN 12 +#define DHCP6_OPTION_IA_TA_LEN 4 + +typedef struct DHCP6Option { + be16_t code; + be16_t len; + uint8_t data[]; +} _packed_ DHCP6Option; + +static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode, + size_t optlen) { + DHCP6Option *option = (DHCP6Option*) *buf; + + assert_return(buf, -EINVAL); + assert_return(*buf, -EINVAL); + assert_return(buflen, -EINVAL); + + if (optlen > 0xffff || *buflen < optlen + sizeof(DHCP6Option)) + return -ENOBUFS; + + option->code = htobe16(optcode); + option->len = htobe16(optlen); + + *buf += sizeof(DHCP6Option); + *buflen -= sizeof(DHCP6Option); + + return 0; +} + +int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, + size_t optlen, const void *optval) { + int r; + + assert_return(optval || optlen == 0, -EINVAL); + + r = option_append_hdr(buf, buflen, code, optlen); + if (r < 0) + return r; + + if (optval) + memcpy(*buf, optval, optlen); + + *buf += optlen; + *buflen -= optlen; + + return 0; +} + +int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { + uint16_t len; + uint8_t *ia_hdr; + size_t ia_buflen, ia_addrlen = 0; + DHCP6Address *addr; + int r; + + assert_return(buf && *buf && buflen && ia, -EINVAL); + + switch (ia->type) { + case DHCP6_OPTION_IA_NA: + len = DHCP6_OPTION_IA_NA_LEN; + break; + + case DHCP6_OPTION_IA_TA: + len = DHCP6_OPTION_IA_TA_LEN; + break; + + default: + return -EINVAL; + } + + if (*buflen < len) + return -ENOBUFS; + + ia_hdr = *buf; + ia_buflen = *buflen; + + *buf += sizeof(DHCP6Option); + *buflen -= sizeof(DHCP6Option); + + memcpy(*buf, &ia->id, len); + + *buf += len; + *buflen -= len; + + LIST_FOREACH(addresses, addr, ia->addresses) { + r = option_append_hdr(buf, buflen, DHCP6_OPTION_IAADDR, + sizeof(addr->iaaddr)); + if (r < 0) + return r; + + memcpy(*buf, &addr->iaaddr, sizeof(addr->iaaddr)); + + *buf += sizeof(addr->iaaddr); + *buflen -= sizeof(addr->iaaddr); + + ia_addrlen += sizeof(DHCP6Option) + sizeof(addr->iaaddr); + } + + r = option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len + ia_addrlen); + if (r < 0) + return r; + + return 0; +} + + +static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen) { + DHCP6Option *option = (DHCP6Option*) *buf; + uint16_t len; + + assert_return(buf, -EINVAL); + assert_return(optcode, -EINVAL); + assert_return(optlen, -EINVAL); + + if (*buflen < sizeof(DHCP6Option)) + return -ENOMSG; + + len = be16toh(option->len); + + if (len > *buflen) + return -ENOMSG; + + *optcode = be16toh(option->code); + *optlen = len; + + *buf += 4; + *buflen -= 4; + + return 0; +} + +int dhcp6_option_parse(uint8_t **buf, size_t *buflen, uint16_t *optcode, + size_t *optlen, uint8_t **optvalue) { + int r; + + assert_return(buf && buflen && optcode && optlen && optvalue, -EINVAL); + + r = option_parse_hdr(buf, buflen, optcode, optlen); + if (r < 0) + return r; + + if (*optlen > *buflen) + return -ENOBUFS; + + *optvalue = *buf; + *buflen -= *optlen; + *buf += *optlen; + + return 0; +} + +int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, + DHCP6IA *ia) { + int r; + uint16_t opt, status; + size_t optlen; + size_t iaaddr_offset; + DHCP6Address *addr; + uint32_t lt_t1, lt_t2, lt_valid, lt_pref, lt_min = ~0; + + assert_return(ia, -EINVAL); + assert_return(!ia->addresses, -EINVAL); + + switch (iatype) { + case DHCP6_OPTION_IA_NA: + + if (*buflen < DHCP6_OPTION_IA_NA_LEN + sizeof(DHCP6Option) + + sizeof(addr->iaaddr)) { + r = -ENOBUFS; + goto error; + } + + iaaddr_offset = DHCP6_OPTION_IA_NA_LEN; + memcpy(&ia->id, *buf, iaaddr_offset); + + lt_t1 = be32toh(ia->lifetime_t1); + lt_t2 = be32toh(ia->lifetime_t2); + + if (lt_t1 && lt_t2 && lt_t1 > lt_t2) { + log_dhcp6_client(client, "IA T1 %ds > T2 %ds", + lt_t1, lt_t2); + r = -EINVAL; + goto error; + } + + break; + + case DHCP6_OPTION_IA_TA: + if (*buflen < DHCP6_OPTION_IA_TA_LEN + sizeof(DHCP6Option) + + sizeof(addr->iaaddr)) { + r = -ENOBUFS; + goto error; + } + + iaaddr_offset = DHCP6_OPTION_IA_TA_LEN; + memcpy(&ia->id, *buf, iaaddr_offset); + + ia->lifetime_t1 = 0; + ia->lifetime_t2 = 0; + + break; + + default: + r = -ENOMSG; + goto error; + } + + ia->type = iatype; + + *buflen -= iaaddr_offset; + *buf += iaaddr_offset; + + while ((r = option_parse_hdr(buf, buflen, &opt, &optlen)) >= 0) { + + switch (opt) { + case DHCP6_OPTION_IAADDR: + + addr = new0(DHCP6Address, 1); + if (!addr) { + r = -ENOMEM; + goto error; + } + + LIST_INIT(addresses, addr); + + memcpy(&addr->iaaddr, *buf, sizeof(addr->iaaddr)); + + lt_valid = be32toh(addr->iaaddr.lifetime_valid); + lt_pref = be32toh(addr->iaaddr.lifetime_valid); + + if (!lt_valid || lt_pref > lt_valid) { + log_dhcp6_client(client, "IA preferred %ds > valid %ds", + lt_pref, lt_valid); + free(addr); + } else { + LIST_PREPEND(addresses, ia->addresses, addr); + if (lt_valid < lt_min) + lt_min = lt_valid; + } + + break; + + case DHCP6_OPTION_STATUS_CODE: + if (optlen < sizeof(status)) + break; + + status = (*buf)[0] << 8 | (*buf)[1]; + if (status) { + log_dhcp6_client(client, "IA status %d", + status); + r = -EINVAL; + goto error; + } + + break; + + default: + log_dhcp6_client(client, "Unknown IA option %d", opt); + break; + } + + *buflen -= optlen; + *buf += optlen; + } + + if (r == -ENOMSG) + r = 0; + + if (!ia->lifetime_t1 && !ia->lifetime_t2) { + lt_t1 = lt_min / 2; + lt_t2 = lt_min / 10 * 8; + ia->lifetime_t1 = htobe32(lt_t1); + ia->lifetime_t2 = htobe32(lt_t2); + + log_dhcp6_client(client, "Computed IA T1 %ds and T2 %ds as both were zero", + lt_t1, lt_t2); + } + + if (*buflen) + r = -ENOMSG; + +error: + *buf += *buflen; + *buflen = 0; + + return r; +} + +int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen, + struct in6_addr **addrs, size_t count, + size_t *allocated) { + + if (optlen == 0 || optlen % sizeof(struct in6_addr) != 0) + return -EINVAL; + + if (!GREEDY_REALLOC(*addrs, *allocated, + count * sizeof(struct in6_addr) + optlen)) + return -ENOMEM; + + memcpy(*addrs + count, optval, optlen); + + count += optlen / sizeof(struct in6_addr); + + return count; +} + +int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char ***str_arr) { + size_t pos = 0, idx = 0; + _cleanup_free_ char **names = NULL; + int r; + + assert_return(optlen > 1, -ENODATA); + assert_return(optval[optlen - 1] == '\0', -EINVAL); + + while (pos < optlen) { + _cleanup_free_ char *ret = NULL; + size_t n = 0, allocated = 0; + bool first = true; + + for (;;) { + uint8_t c; + + c = optval[pos++]; + + if (c == 0) + /* End of name */ + break; + else if (c <= 63) { + const char *label; + + /* Literal label */ + label = (const char *)&optval[pos]; + pos += c; + if (pos > optlen) + return -EMSGSIZE; + + if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) { + r = -ENOMEM; + goto fail; + } + + if (first) + first = false; + else + ret[n++] = '.'; + + r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + goto fail; + + n += r; + continue; + } else { + r = -EBADMSG; + goto fail; + } + } + + if (!GREEDY_REALLOC(ret, allocated, n + 1)) { + r = -ENOMEM; + goto fail; + } + + ret[n] = 0; + + r = strv_extend(&names, ret); + if (r < 0) + goto fail; + + idx++; + } + + *str_arr = names; + names = NULL; + + return idx; + +fail: + return r; +} diff --git a/src/systemd/src/libsystemd-network/dhcp6-protocol.h b/src/systemd/src/libsystemd-network/dhcp6-protocol.h new file mode 100644 index 00000000..1318c816 --- /dev/null +++ b/src/systemd/src/libsystemd-network/dhcp6-protocol.h @@ -0,0 +1,152 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +#include "macro.h" +#include "sparse-endian.h" + +struct DHCP6Message { + union { + struct { + uint8_t type; + uint8_t _pad[3]; + } _packed_; + be32_t transaction_id; + }; +} _packed_; + +typedef struct DHCP6Message DHCP6Message; + +#define DHCP6_MIN_OPTIONS_SIZE \ + 1280 - sizeof(struct ip6_hdr) - sizeof(struct udphdr) + +#define IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT \ + { { { 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02 } } } + +enum { + DHCP6_PORT_SERVER = 547, + DHCP6_PORT_CLIENT = 546, +}; + +#define DHCP6_INF_TIMEOUT 1 * USEC_PER_SEC +#define DHCP6_INF_MAX_RT 120 * USEC_PER_SEC +#define DHCP6_SOL_MAX_DELAY 1 * USEC_PER_SEC +#define DHCP6_SOL_TIMEOUT 1 * USEC_PER_SEC +#define DHCP6_SOL_MAX_RT 120 * USEC_PER_SEC +#define DHCP6_REQ_TIMEOUT 1 * USEC_PER_SEC +#define DHCP6_REQ_MAX_RT 120 * USEC_PER_SEC +#define DHCP6_REQ_MAX_RC 10 +#define DHCP6_REN_TIMEOUT 10 * USEC_PER_SEC +#define DHCP6_REN_MAX_RT 600 * USEC_PER_SEC +#define DHCP6_REB_TIMEOUT 10 * USEC_PER_SEC +#define DHCP6_REB_MAX_RT 600 * USEC_PER_SEC + +enum { + DHCP6_DUID_LLT = 1, + DHCP6_DUID_EN = 2, + DHCP6_DUID_LL = 3, + DHCP6_DUID_UUID = 4, +}; + +enum DHCP6State { + DHCP6_STATE_STOPPED = 0, + DHCP6_STATE_INFORMATION_REQUEST = 1, + DHCP6_STATE_SOLICITATION = 2, + DHCP6_STATE_REQUEST = 3, + DHCP6_STATE_BOUND = 4, + DHCP6_STATE_RENEW = 5, + DHCP6_STATE_REBIND = 6, +}; + +enum { + DHCP6_SOLICIT = 1, + DHCP6_ADVERTISE = 2, + DHCP6_REQUEST = 3, + DHCP6_CONFIRM = 4, + DHCP6_RENEW = 5, + DHCP6_REBIND = 6, + DHCP6_REPLY = 7, + DHCP6_RELEASE = 8, + DHCP6_DECLINE = 9, + DHCP6_RECONFIGURE = 10, + DHCP6_INFORMATION_REQUEST = 11, + DHCP6_RELAY_FORW = 12, + DHCP6_RELAY_REPL = 13, + _DHCP6_MESSAGE_MAX = 14, +}; + +enum { + DHCP6_OPTION_CLIENTID = 1, + DHCP6_OPTION_SERVERID = 2, + DHCP6_OPTION_IA_NA = 3, + DHCP6_OPTION_IA_TA = 4, + DHCP6_OPTION_IAADDR = 5, + DHCP6_OPTION_ORO = 6, + DHCP6_OPTION_PREFERENCE = 7, + DHCP6_OPTION_ELAPSED_TIME = 8, + DHCP6_OPTION_RELAY_MSG = 9, + /* option code 10 is unassigned */ + DHCP6_OPTION_AUTH = 11, + DHCP6_OPTION_UNICAST = 12, + DHCP6_OPTION_STATUS_CODE = 13, + DHCP6_OPTION_RAPID_COMMIT = 14, + DHCP6_OPTION_USER_CLASS = 15, + DHCP6_OPTION_VENDOR_CLASS = 16, + DHCP6_OPTION_VENDOR_OPTS = 17, + DHCP6_OPTION_INTERFACE_ID = 18, + DHCP6_OPTION_RECONF_MSG = 19, + DHCP6_OPTION_RECONF_ACCEPT = 20, + + DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */ + DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */ + + DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075, deprecated */ + + /* option code 35 is unassigned */ + + DHCP6_OPTION_NTP_SERVER = 56, /* RFC 5908 */ + + /* option codes 89-142 are unassigned */ + /* option codes 144-65535 are unassigned */ +}; + +enum { + DHCP6_NTP_SUBOPTION_SRV_ADDR = 1, + DHCP6_NTP_SUBOPTION_MC_ADDR = 2, + DHCP6_NTP_SUBOPTION_SRV_FQDN = 3, +}; + +enum { + DHCP6_STATUS_SUCCESS = 0, + DHCP6_STATUS_UNSPEC_FAIL = 1, + DHCP6_STATUS_NO_ADDRS_AVAIL = 2, + DHCP6_STATUS_NO_BINDING = 3, + DHCP6_STATUS_NOT_ON_LINK = 4, + DHCP6_STATUS_USE_MULTICAST = 5, + _DHCP6_STATUS_MAX = 6, +}; diff --git a/src/systemd/src/libsystemd-network/lldp-internal.c b/src/systemd/src/libsystemd-network/lldp-internal.c new file mode 100644 index 00000000..87fecd0a --- /dev/null +++ b/src/systemd/src/libsystemd-network/lldp-internal.c @@ -0,0 +1,364 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014 Susant Sahani + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include "sd-lldp.h" + +#include "alloc-util.h" +#include "lldp-internal.h" + +/* We store maximum 1K chassis entries */ +#define LLDP_MIB_MAX_CHASSIS 1024 + +/* Maximum Ports can be attached to any chassis */ +#define LLDP_MIB_MAX_PORT_PER_CHASSIS 32 + +/* 10.5.5.2.2 mibUpdateObjects () + * The mibUpdateObjects () procedure updates the MIB objects corresponding to + * the TLVs contained in the received LLDPDU for the LLDP remote system + * indicated by the LLDP remote systems update process defined in 10.3.5 */ + +int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) { + lldp_neighbour_port *p; + uint16_t length, ttl; + uint8_t *data; + uint8_t type; + int r; + + assert_return(c, -EINVAL); + assert_return(tlv, -EINVAL); + + r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); + if (r < 0) + return r; + + /* Update the packet if we already have */ + LIST_FOREACH(port, p, c->ports) { + + if ((p->type == type && p->length == length && !memcmp(p->data, data, p->length))) { + + r = sd_lldp_packet_read_ttl(tlv, &ttl); + if (r < 0) + return r; + + p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic()); + + sd_lldp_packet_unref(p->packet); + p->packet = tlv; + + prioq_reshuffle(p->c->by_expiry, p, &p->prioq_idx); + + return 0; + } + } + + return -1; +} + +int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv) { + lldp_neighbour_port *p, *q; + uint8_t *data; + uint16_t length; + uint8_t type; + int r; + + assert_return(c, -EINVAL); + assert_return(tlv, -EINVAL); + + r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); + if (r < 0) + return r; + + LIST_FOREACH_SAFE(port, p, q, c->ports) { + + /* Find the port */ + if (p->type == type && p->length == length && !memcmp(p->data, data, p->length)) { + lldp_neighbour_port_remove_and_free(p); + break; + } + } + + return 0; +} + +int lldp_mib_add_objects(Prioq *by_expiry, + Hashmap *neighbour_mib, + tlv_packet *tlv) { + _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL; + _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL; + lldp_chassis_id chassis_id; + bool new_chassis = false; + uint8_t subtype, *data; + uint16_t ttl, length; + int r; + + assert_return(by_expiry, -EINVAL); + assert_return(neighbour_mib, -EINVAL); + assert_return(tlv, -EINVAL); + + r = sd_lldp_packet_read_chassis_id(tlv, &subtype, &data, &length); + if (r < 0) + goto drop; + + r = sd_lldp_packet_read_ttl(tlv, &ttl); + if (r < 0) + goto drop; + + /* Make hash key */ + chassis_id.type = subtype; + chassis_id.length = length; + chassis_id.data = data; + + /* Try to find the Chassis */ + c = hashmap_get(neighbour_mib, &chassis_id); + if (!c) { + + /* Don't create chassis if ttl 0 is received . Silently drop it */ + if (ttl == 0) { + log_lldp("TTL value 0 received. Skiping Chassis creation."); + goto drop; + } + + /* Admission Control: Can we store this packet ? */ + if (hashmap_size(neighbour_mib) >= LLDP_MIB_MAX_CHASSIS) { + + log_lldp("Exceeding number of chassie: %d. Dropping ...", + hashmap_size(neighbour_mib)); + goto drop; + } + + r = lldp_chassis_new(tlv, by_expiry, neighbour_mib, &c); + if (r < 0) + goto drop; + + new_chassis = true; + + r = hashmap_put(neighbour_mib, &c->chassis_id, c); + if (r < 0) + goto drop; + + } else { + + /* When the TTL field is set to zero, the receiving LLDP agent is notified all + * system information associated with the LLDP agent/port is to be deleted */ + if (ttl == 0) { + log_lldp("TTL value 0 received . Deleting associated Port ..."); + + lldp_mib_remove_objects(c, tlv); + + c = NULL; + goto drop; + } + + /* if we already have this port just update it */ + r = lldp_mib_update_objects(c, tlv); + if (r >= 0) { + c = NULL; + return r; + } + + /* Admission Control: Can this port attached to the existing chassis ? */ + if (c->n_ref >= LLDP_MIB_MAX_PORT_PER_CHASSIS) { + log_lldp("Port limit reached. Chassis has: %d ports. Dropping ...", c->n_ref); + + c = NULL; + goto drop; + } + } + + /* This is a new port */ + r = lldp_neighbour_port_new(c, tlv, &p); + if (r < 0) + goto drop; + + r = prioq_put(c->by_expiry, p, &p->prioq_idx); + if (r < 0) + goto drop; + + /* Attach new port to chassis */ + LIST_PREPEND(port, c->ports, p); + c->n_ref ++; + + p = NULL; + c = NULL; + + return 0; + + drop: + sd_lldp_packet_unref(tlv); + + if (new_chassis) + hashmap_remove(neighbour_mib, &c->chassis_id); + + return r; +} + +void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p) { + lldp_chassis *c; + + assert(p); + assert(p->c); + + c = p->c; + + prioq_remove(c->by_expiry, p, &p->prioq_idx); + + LIST_REMOVE(port, c->ports, p); + lldp_neighbour_port_free(p); + + /* Drop the Chassis if no port is attached */ + c->n_ref --; + if (c->n_ref <= 1) { + hashmap_remove(c->neighbour_mib, &c->chassis_id); + lldp_chassis_free(c); + } +} + +void lldp_neighbour_port_free(lldp_neighbour_port *p) { + + if(!p) + return; + + sd_lldp_packet_unref(p->packet); + + free(p->data); + free(p); +} + +int lldp_neighbour_port_new(lldp_chassis *c, + tlv_packet *tlv, + lldp_neighbour_port **ret) { + _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL; + uint16_t length, ttl; + uint8_t *data; + uint8_t type; + int r; + + assert(tlv); + + r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); + if (r < 0) + return r; + + r = sd_lldp_packet_read_ttl(tlv, &ttl); + if (r < 0) + return r; + + p = new0(lldp_neighbour_port, 1); + if (!p) + return -ENOMEM; + + p->c = c; + p->type = type; + p->length = length; + p->packet = tlv; + p->prioq_idx = PRIOQ_IDX_NULL; + p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic()); + + p->data = memdup(data, length); + if (!p->data) + return -ENOMEM; + + *ret = p; + p = NULL; + + return 0; +} + +void lldp_chassis_free(lldp_chassis *c) { + + if (!c) + return; + + if (c->n_ref > 1) + return; + + free(c->chassis_id.data); + free(c); +} + +int lldp_chassis_new(tlv_packet *tlv, + Prioq *by_expiry, + Hashmap *neighbour_mib, + lldp_chassis **ret) { + _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL; + uint16_t length; + uint8_t *data; + uint8_t type; + int r; + + assert(tlv); + + r = sd_lldp_packet_read_chassis_id(tlv, &type, &data, &length); + if (r < 0) + return r; + + c = new0(lldp_chassis, 1); + if (!c) + return -ENOMEM; + + c->n_ref = 1; + c->chassis_id.type = type; + c->chassis_id.length = length; + + c->chassis_id.data = memdup(data, length); + if (!c->chassis_id.data) + return -ENOMEM; + + LIST_HEAD_INIT(c->ports); + + c->by_expiry = by_expiry; + c->neighbour_mib = neighbour_mib; + + *ret = c; + c = NULL; + + return 0; +} + +int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_(sd_lldp_packet_unrefp) tlv_packet *packet = NULL; + tlv_packet *p; + uint16_t length; + int r; + + assert(fd); + assert(userdata); + + r = tlv_packet_new(&packet); + if (r < 0) + return r; + + length = read(fd, &packet->pdu, sizeof(packet->pdu)); + + /* Silently drop the packet */ + if ((size_t) length > ETHER_MAX_LEN) + return 0; + + packet->userdata = userdata; + + p = packet; + packet = NULL; + + return lldp_handle_packet(p, (uint16_t) length); +} diff --git a/src/systemd/src/libsystemd-network/lldp-internal.h b/src/systemd/src/libsystemd-network/lldp-internal.h new file mode 100644 index 00000000..5496fae7 --- /dev/null +++ b/src/systemd/src/libsystemd-network/lldp-internal.h @@ -0,0 +1,95 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014 Susant Sahani + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#pragma once + +#include "nm-sd-adapt.h" + +#include "sd-event.h" + +#include "list.h" +#include "lldp-tlv.h" +#include "log.h" +#include "prioq.h" + +typedef struct lldp_neighbour_port lldp_neighbour_port; +typedef struct lldp_chassis lldp_chassis; +typedef struct lldp_chassis_id lldp_chassis_id; +typedef struct lldp_agent_statistics lldp_agent_statistics; + +struct lldp_neighbour_port { + uint8_t type; + uint8_t *data; + + uint16_t length; + usec_t until; + + unsigned prioq_idx; + + lldp_chassis *c; + tlv_packet *packet; + + LIST_FIELDS(lldp_neighbour_port, port); +}; + +int lldp_neighbour_port_new(lldp_chassis *c, tlv_packet *tlv, lldp_neighbour_port **ret); +void lldp_neighbour_port_free(lldp_neighbour_port *p); +void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p); + +DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_neighbour_port *, lldp_neighbour_port_free); +#define _cleanup_lldp_neighbour_port_free_ _cleanup_(lldp_neighbour_port_freep) + +struct lldp_chassis_id { + uint8_t type; + uint16_t length; + + uint8_t *data; +}; + +struct lldp_chassis { + unsigned n_ref; + + lldp_chassis_id chassis_id; + + Prioq *by_expiry; + Hashmap *neighbour_mib; + + LIST_HEAD(lldp_neighbour_port, ports); +}; + +int lldp_chassis_new(tlv_packet *tlv, + Prioq *by_expiry, + Hashmap *neighbour_mib, + lldp_chassis **ret); + +void lldp_chassis_free(lldp_chassis *c); + +DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_chassis *, lldp_chassis_free); +#define _cleanup_lldp_chassis_free_ _cleanup_(lldp_chassis_freep) + +int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv); +int lldp_mib_add_objects(Prioq *by_expiry, Hashmap *neighbour_mib, tlv_packet *tlv); +int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv); + +int lldp_handle_packet(tlv_packet *m, uint16_t length); +int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata); +#define log_lldp(fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) diff --git a/src/systemd/src/libsystemd-network/lldp-network.c b/src/systemd/src/libsystemd-network/lldp-network.c new file mode 100644 index 00000000..e7f575a0 --- /dev/null +++ b/src/systemd/src/libsystemd-network/lldp-network.c @@ -0,0 +1,87 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014 Susant Sahani + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +#include "fd-util.h" +#include "lldp-internal.h" +#include "lldp-network.h" +#include "lldp-tlv.h" +#include "socket-util.h" + +int lldp_network_bind_raw_socket(int ifindex) { + typedef struct LLDPFrame { + struct ethhdr hdr; + uint8_t tlvs[0]; + } LLDPFrame; + + struct sock_filter filter[] = { + BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(LLDPFrame, hdr.h_dest)), /* A <- 4 bytes of destination MAC */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0180c200, 1, 0), /* A != 01:80:c2:00 */ + BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(LLDPFrame, hdr.h_dest) + 4), /* A <- remaining 2 bytes of destination MAC */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0000, 3, 0), /* A != 00:00 */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x0003, 2, 0), /* A != 00:03 */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0x000e, 1, 0), /* A != 00:0e */ + BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(LLDPFrame, hdr.h_proto)), /* A <- protocol */ + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_LLDP, 1, 0), /* A != ETHERTYPE_LLDP */ + BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ + BPF_STMT(BPF_RET + BPF_K, (uint32_t) -1), /* accept packet */ + }; + + struct sock_fprog fprog = { + .len = ELEMENTSOF(filter), + .filter = filter + }; + + _cleanup_close_ int s = -1; + + union sockaddr_union saddrll = { + .ll.sll_family = AF_PACKET, + .ll.sll_ifindex = ifindex, + }; + + int r; + + assert(ifindex > 0); + + s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + if (s < 0) + return -errno; + + r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); + if (r < 0) + return -errno; + + r = bind(s, &saddrll.sa, sizeof(saddrll.ll)); + if (r < 0) + return -errno; + + r = s; + s = -1; + + return r; +} diff --git a/src/systemd/src/libsystemd-network/lldp-network.h b/src/systemd/src/libsystemd-network/lldp-network.h new file mode 100644 index 00000000..b1e428e7 --- /dev/null +++ b/src/systemd/src/libsystemd-network/lldp-network.h @@ -0,0 +1,29 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014 Susant Sahani + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#pragma once + +#include "nm-sd-adapt.h" + +#include "sd-event.h" + +int lldp_network_bind_raw_socket(int ifindex); diff --git a/src/systemd/src/libsystemd-network/lldp-port.c b/src/systemd/src/libsystemd-network/lldp-port.c new file mode 100644 index 00000000..7374f18d --- /dev/null +++ b/src/systemd/src/libsystemd-network/lldp-port.c @@ -0,0 +1,120 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014 Susant Sahani + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include "alloc-util.h" +#include "async.h" +#include "lldp-internal.h" +#include "lldp-network.h" +#include "lldp-port.h" + +int lldp_port_start(lldp_port *p) { + int r; + + assert_return(p, -EINVAL); + + r = lldp_network_bind_raw_socket(p->ifindex); + if (r < 0) + return r; + + p->rawfd = r; + + r = sd_event_add_io(p->event, &p->lldp_port_rx, + p->rawfd, EPOLLIN, lldp_receive_packet, p); + if (r < 0) { + log_debug_errno(r, "Failed to allocate event source: %m"); + goto fail; + } + + r = sd_event_source_set_priority(p->lldp_port_rx, p->event_priority); + if (r < 0) { + log_debug_errno(r, "Failed to set event priority: %m"); + goto fail; + } + + r = sd_event_source_set_description(p->lldp_port_rx, "lldp-port-rx"); + if (r < 0) { + log_debug_errno(r, "Failed to set event name: %m"); + goto fail; + } + + return 0; + +fail: + lldp_port_stop(p); + + return r; +} + +int lldp_port_stop(lldp_port *p) { + + assert_return(p, -EINVAL); + + p->rawfd = asynchronous_close(p->rawfd); + p->lldp_port_rx = sd_event_source_unref(p->lldp_port_rx); + + return 0; +} + +void lldp_port_free(lldp_port *p) { + if (!p) + return; + + lldp_port_stop(p); + + free(p->ifname); + free(p); +} + +int lldp_port_new(int ifindex, + const char *ifname, + const struct ether_addr *addr, + void *userdata, + lldp_port **ret) { + _cleanup_free_ lldp_port *p = NULL; + + assert_return(ifindex, -EINVAL); + assert_return(ifname, -EINVAL); + assert_return(addr, -EINVAL); + + p = new0(lldp_port, 1); + if (!p) + return -ENOMEM; + + p->rawfd = -1; + p->ifindex = ifindex; + + p->ifname = strdup(ifname); + if (!p->ifname) + return -ENOMEM; + + memcpy(&p->mac, addr, ETH_ALEN); + + p->userdata = userdata; + + *ret = p; + + p = NULL; + + return 0; +} diff --git a/src/systemd/src/libsystemd-network/lldp-port.h b/src/systemd/src/libsystemd-network/lldp-port.h new file mode 100644 index 00000000..063eaa27 --- /dev/null +++ b/src/systemd/src/libsystemd-network/lldp-port.h @@ -0,0 +1,73 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014 Susant Sahani + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#pragma once + +#include "nm-sd-adapt.h" + +#include + +#include "sd-event.h" +#include "sd-lldp.h" + +#include "util.h" + +typedef struct lldp_port lldp_port; + +typedef enum LLDPPortStatus { + LLDP_PORT_STATUS_NONE, + LLDP_PORT_STATUS_ENABLED, + LLDP_PORT_STATUS_DISABLED, + _LLDP_PORT_STATUS_MAX, + _LLDP_PORT_STATUS_INVALID = -1, +} LLDPPortStatus; + +struct lldp_port { + LLDPPortStatus status; + + int ifindex; + char *ifname; + + struct ether_addr mac; + + int rawfd; + + sd_event *event; + sd_event_source *lldp_port_rx; + + int event_priority; + + void *userdata; +}; + +int lldp_port_new(int ifindex, + const char *ifname, + const struct ether_addr *addr, + void *userdata, + lldp_port **ret); +void lldp_port_free(lldp_port *p); + +DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_port*, lldp_port_free); +#define _cleanup_lldp_port_free_ _cleanup_(lldp_port_freep) + +int lldp_port_start(lldp_port *p); +int lldp_port_stop(lldp_port *p); diff --git a/src/systemd/src/libsystemd-network/lldp-tlv.c b/src/systemd/src/libsystemd-network/lldp-tlv.c new file mode 100644 index 00000000..b589402f --- /dev/null +++ b/src/systemd/src/libsystemd-network/lldp-tlv.c @@ -0,0 +1,642 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014 Susant Sahani + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +#include "alloc-util.h" +#include "lldp-tlv.h" +#include "macro.h" + +int tlv_section_new(tlv_section **ret) { + tlv_section *s; + + s = new0(tlv_section, 1); + if (!s) + return -ENOMEM; + + *ret = s; + + return 0; +} + +void tlv_section_free(tlv_section *m) { + + if (!m) + return; + + free(m); +} + +int tlv_packet_new(tlv_packet **ret) { + tlv_packet *m; + + m = new0(tlv_packet, 1); + if (!m) + return -ENOMEM; + + LIST_HEAD_INIT(m->sections); + m->n_ref = 1; + + *ret = m; + + return 0; +} + +tlv_packet *sd_lldp_packet_ref(tlv_packet *m) { + + if (!m) + return NULL; + + assert(m->n_ref > 0); + m->n_ref++; + + return m; +} + +tlv_packet *sd_lldp_packet_unref(tlv_packet *m) { + tlv_section *s, *n; + + if (!m) + return NULL; + + assert(m->n_ref > 0); + m->n_ref--; + + if (m->n_ref > 0) + return m; + + LIST_FOREACH_SAFE(section, s, n, m->sections) + tlv_section_free(s); + + free(m); + return NULL; +} + +int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length) { + uint8_t *p; + + assert_return(m, -EINVAL); + assert_return(data, -EINVAL); + assert_return(data_length, -EINVAL); + + if (m->length + data_length > ETHER_MAX_LEN) + return -ENOMEM; + + p = m->pdu + m->length; + memcpy(p, data, data_length); + m->length += data_length; + + return 0; +} + +int tlv_packet_append_u8(tlv_packet *m, uint8_t data) { + + assert_return(m, -EINVAL); + + return tlv_packet_append_bytes(m, &data, sizeof(uint8_t)); +} + +int tlv_packet_append_u16(tlv_packet *m, uint16_t data) { + uint16_t type; + + assert_return(m, -EINVAL); + + type = htons(data); + + return tlv_packet_append_bytes(m, &type, sizeof(uint16_t)); +} + +int tlv_packet_append_u32(tlv_packet *m, uint32_t data) { + uint32_t type; + + assert_return(m, -EINVAL); + + type = htonl(data); + + return tlv_packet_append_bytes(m, &type, sizeof(uint32_t)); +} + +int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size) { + + assert_return(m, -EINVAL); + + return tlv_packet_append_bytes(m, data, size); +} + +int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type) { + + assert_return(m, -EINVAL); + + m->container_pos = m->pdu + m->length; + + return tlv_packet_append_u16(m, type << 9); +} + +int lldp_tlv_packet_close_container(tlv_packet *m) { + uint16_t type; + + assert_return(m, -EINVAL); + assert_return(m->container_pos, -EINVAL); + + memcpy(&type, m->container_pos, sizeof(uint16_t)); + + type |= htons(((m->pdu + m->length) - (m->container_pos + 2)) & 0x01ff); + memcpy(m->container_pos, &type, sizeof(uint16_t)); + + return 0; +} + +static inline int tlv_packet_read_internal(tlv_section *m, void **data) { + + assert_return(m->read_pos, -EINVAL); + + *data = m->read_pos; + + return 0; +} + +int tlv_packet_read_u8(tlv_packet *m, uint8_t *data) { + void *val = NULL; + int r; + + assert_return(m, -EINVAL); + + r = tlv_packet_read_internal(m->container, &val); + if (r < 0) + return r; + + memcpy(data, val, sizeof(uint8_t)); + + m->container->read_pos ++; + + return 0; +} + +int tlv_packet_read_u16(tlv_packet *m, uint16_t *data) { + uint16_t t; + void *val = NULL; + int r; + + assert_return(m, -EINVAL); + + r = tlv_packet_read_internal(m->container, &val); + if (r < 0) + return r; + + memcpy(&t, val, sizeof(uint16_t)); + *data = ntohs(t); + + m->container->read_pos += 2; + + return 0; +} + +int tlv_packet_read_u32(tlv_packet *m, uint32_t *data) { + uint32_t t; + void *val; + int r; + + assert_return(m, -EINVAL); + + r = tlv_packet_read_internal(m->container, &val); + if (r < 0) + return r; + + memcpy(&t, val, sizeof(uint32_t)); + *data = ntohl(t); + + m->container->read_pos += 4; + + return r; +} + +int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) { + void *val = NULL; + int r; + + assert_return(m, -EINVAL); + + r = tlv_packet_read_internal(m->container, &val); + if (r < 0) + return r; + + *data = (char *) val; + *data_length = m->container->data + m->container->length - m->container->read_pos; + + m->container->read_pos += *data_length; + + return 0; +} + +int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length) { + void *val = NULL; + int r; + + assert_return(m, -EINVAL); + + r = tlv_packet_read_internal(m->container, &val); + if (r < 0) + return r; + + *data = (uint8_t *) val; + *data_length = m->container->data + m->container->length - m->container->read_pos; + + m->container->read_pos += *data_length; + + return 0; +} + +/* parse raw TLV packet */ +int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) { + tlv_section *section, *tail; + uint16_t t, l; + uint8_t *p; + int r; + + assert_return(m, -EINVAL); + assert_return(size, -EINVAL); + + p = m->pdu; + + /* extract Ethernet header */ + memcpy(&m->mac, p, ETH_ALEN); + p += sizeof(struct ether_header); + + for (l = 0; l <= size; ) { + r = tlv_section_new(§ion); + if (r < 0) + return r; + + memcpy(&t, p, sizeof(uint16_t)); + + section->type = ntohs(t) >> 9; + section->length = ntohs(t) & 0x01ff; + + if (section->type == LLDP_TYPE_END || section->type >=_LLDP_TYPE_MAX) { + tlv_section_free(section); + break; + } + + p += 2; + + if (section->type == LLDP_TYPE_PRIVATE && + section->length >= LLDP_OUI_LEN + 1) { + section->oui = p; + p += LLDP_OUI_LEN; + section->subtype = *p++; + + section->length -= LLDP_OUI_LEN + 1; + l += LLDP_OUI_LEN + 1; + } + + section->data = p; + + LIST_FIND_TAIL(section, m->sections, tail); + LIST_INSERT_AFTER(section, m->sections, tail, section); + + p += section->length; + l += (section->length + 2); + } + + return 0; +} + +int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type) { + tlv_section *s; + + assert_return(m, -EINVAL); + assert_return(type != LLDP_TYPE_PRIVATE, -EINVAL); + + LIST_FOREACH(section, s, m->sections) + if (s->type == type) + break; + if (!s) + return -1; + + m->container = s; + + m->container->read_pos = s->data; + if (!m->container->read_pos) { + m->container = NULL; + return -1; + } + + return 0; +} + +int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype) { + tlv_section *s; + + assert_return(m, -EINVAL); + assert_return(oui, -EINVAL); + + LIST_FOREACH(section, s, m->sections) { + if (s->type == LLDP_TYPE_PRIVATE && + s->oui && + s->subtype == subtype && + !memcmp(s->oui, oui, LLDP_OUI_LEN)) + break; + } + + if (!s) + return -1; + + m->container = s; + + m->container->read_pos = s->data; + if (!m->container->read_pos) { + m->container = NULL; + return -1; + } + + return 0; +} + +int lldp_tlv_packet_exit_container(tlv_packet *m) { + assert_return(m, -EINVAL); + + m->container = 0; + + return 0; +} + +static int lldp_tlv_packet_read_u16_tlv(tlv_packet *tlv, uint16_t type, uint16_t *value) { + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container(tlv, type); + if (r < 0) + return r; + + r = tlv_packet_read_u16(tlv, value); + r2 = lldp_tlv_packet_exit_container(tlv); + + return r < 0 ? r : r2; +} + +static int lldp_tlv_packet_read_string_tlv(tlv_packet *tlv, uint16_t type, char **data, uint16_t *length) { + char *s; + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container(tlv, type); + if (r < 0) + return r; + + r = tlv_packet_read_string(tlv, &s, length); + if (r < 0) + goto out; + + *data = (char *) s; + + out: + r2 = lldp_tlv_packet_exit_container(tlv); + + return r < 0 ? r : r2; +} + +int sd_lldp_packet_read_chassis_id(tlv_packet *tlv, + uint8_t *type, + uint8_t **data, + uint16_t *length) { + uint8_t subtype; + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID); + if (r < 0) + return r; + + r = tlv_packet_read_u8(tlv, &subtype); + if (r < 0) + goto out; + + switch (subtype) { + case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: + + r = tlv_packet_read_bytes(tlv, data, length); + if (r < 0) + goto out; + + break; + default: + r = -EOPNOTSUPP; + break; + } + + *type = subtype; + + out: + r2 = lldp_tlv_packet_exit_container(tlv); + + return r < 0 ? r : r2; +} + +int sd_lldp_packet_read_port_id(tlv_packet *tlv, + uint8_t *type, + uint8_t **data, + uint16_t *length) { + uint8_t subtype; + char *s; + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID); + if (r < 0) + return r; + + r = tlv_packet_read_u8(tlv, &subtype); + if (r < 0) + goto out; + + switch (subtype) { + case LLDP_PORT_SUBTYPE_PORT_COMPONENT: + case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: + case LLDP_PORT_SUBTYPE_INTERFACE_NAME: + case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: + + r = tlv_packet_read_string(tlv, &s, length); + if (r < 0) + goto out; + + *data = (uint8_t *) s; + + break; + case LLDP_PORT_SUBTYPE_MAC_ADDRESS: + + r = tlv_packet_read_bytes(tlv, data, length); + if (r < 0) + goto out; + + break; + default: + r = -EOPNOTSUPP; + break; + } + + *type = subtype; + + out: + r2 = lldp_tlv_packet_exit_container(tlv); + + return r < 0 ? r : r2; +} + +int sd_lldp_packet_read_ttl(tlv_packet *tlv, uint16_t *ttl) { + return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_TTL, ttl); +} + +int sd_lldp_packet_read_system_name(tlv_packet *tlv, + char **data, + uint16_t *length) { + return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_NAME, data, length); +} + +int sd_lldp_packet_read_system_description(tlv_packet *tlv, + char **data, + uint16_t *length) { + return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_DESCRIPTION, data, length); +} + +int sd_lldp_packet_read_port_description(tlv_packet *tlv, + char **data, + uint16_t *length) { + return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_PORT_DESCRIPTION, data, length); +} + +int sd_lldp_packet_read_system_capability(tlv_packet *tlv, uint16_t *data) { + return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_SYSTEM_CAPABILITIES, data); +} + +int sd_lldp_packet_read_port_vlan_id(tlv_packet *tlv, uint16_t *id) { + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID); + if (r < 0) + return r; + + r = tlv_packet_read_u16(tlv, id); + r2 = lldp_tlv_packet_exit_container(tlv); + + return r < 0 ? r : r2; +} + +int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id) { + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID); + if (r < 0) + return r; + + r = tlv_packet_read_u8(tlv, flags); + if (r >= 0) + r = tlv_packet_read_u16(tlv, id); + + r2 = lldp_tlv_packet_exit_container(tlv); + + return r < 0 ? r : r2; +} + +int sd_lldp_packet_read_vlan_name(tlv_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length) { + int r, r2; + uint8_t len = 0; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_VLAN_NAME); + if (r < 0) + return r; + + r = tlv_packet_read_u16(tlv, vlan_id); + if (r >= 0) + r = tlv_packet_read_u8(tlv, &len); + if (r >= 0) + r = tlv_packet_read_string(tlv, name, length); + + if (r >= 0 && len < *length) + *length = len; + + r2 = lldp_tlv_packet_exit_container(tlv); + + return r < 0 ? r : r2; +} + +int sd_lldp_packet_read_management_vid(tlv_packet *tlv, uint16_t *id) { + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID); + if (r < 0) + return r; + + r = tlv_packet_read_u16(tlv, id); + r2 = lldp_tlv_packet_exit_container(tlv); + + return r < 0 ? r : r2; +} + +int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id) { + int r, r2; + + assert_return(tlv, -EINVAL); + + r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION); + if (r < 0) + return r; + + r = tlv_packet_read_u8(tlv, status); + if (r >= 0) + r = tlv_packet_read_u32(tlv, id); + + r2 = lldp_tlv_packet_exit_container(tlv); + + return r < 0 ? r : r2; +} + +int sd_lldp_packet_get_destination_type(tlv_packet *tlv, int *dest) { + assert_return(tlv, -EINVAL); + assert_return(dest, -EINVAL); + + /* 802.1AB-2009, Table 7-1 */ + if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_BRIDGE, ETH_ALEN)) + *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE; + else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE, ETH_ALEN)) + *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE; + else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE, ETH_ALEN)) + *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE; + else + return -EINVAL; + + return 0; +} diff --git a/src/systemd/src/libsystemd-network/lldp-tlv.h b/src/systemd/src/libsystemd-network/lldp-tlv.h new file mode 100644 index 00000000..7d7459e9 --- /dev/null +++ b/src/systemd/src/libsystemd-network/lldp-tlv.h @@ -0,0 +1,98 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014 Susant Sahani + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#pragma once + +#include "nm-sd-adapt.h" + +#include + +#include "sd-lldp.h" + +#include "list.h" +#include "lldp.h" +#include "util.h" + +typedef struct sd_lldp_packet tlv_packet; +typedef struct sd_lldp_section tlv_section; + +#define LLDP_OUI_LEN 3 + +struct sd_lldp_section { + uint16_t type; + uint16_t length; + uint8_t *oui; + uint8_t subtype; + + uint8_t *read_pos; + uint8_t *data; + + LIST_FIELDS(tlv_section, section); +}; + +#define LLDP_MAC_NEAREST_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } +#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 } +#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 } + +int tlv_section_new(tlv_section **ret); +void tlv_section_free(tlv_section *ret); + +struct sd_lldp_packet { + unsigned n_ref; + + uint16_t type; + uint16_t length; + usec_t ts; + + uint8_t *container_pos; + uint8_t pdu[ETHER_MAX_LEN]; + + void *userdata; + + struct ether_addr mac; + tlv_section *container; + + LIST_HEAD(tlv_section, sections); +}; + +int tlv_packet_new(tlv_packet **ret); + +int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type); +int lldp_tlv_packet_close_container(tlv_packet *m); + +int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length); +int tlv_packet_append_u8(tlv_packet *m, uint8_t data); +int tlv_packet_append_u16(tlv_packet *m, uint16_t data); +int tlv_packet_append_u32(tlv_packet *m, uint32_t data); +int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size); + +int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type); +int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype); +int lldp_tlv_packet_exit_container(tlv_packet *m); + +int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length); +int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length); +int tlv_packet_read_u8(tlv_packet *m, uint8_t *data); +int tlv_packet_read_u16(tlv_packet *m, uint16_t *data); +int tlv_packet_read_u32(tlv_packet *m, uint32_t *data); + +int tlv_packet_parse_pdu(tlv_packet *t, uint16_t size); diff --git a/src/systemd/src/libsystemd-network/lldp.h b/src/systemd/src/libsystemd-network/lldp.h new file mode 100644 index 00000000..974fd8b0 --- /dev/null +++ b/src/systemd/src/libsystemd-network/lldp.h @@ -0,0 +1,130 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014 Susant Sahani + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#pragma once + +#include "nm-sd-adapt.h" + +#define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } + +#define ETHERTYPE_LLDP 0x88cc + +/* IEEE 802.3AB Clause 9: TLV Types */ +typedef enum LLDPTypes { + LLDP_TYPE_END = 0, + LLDP_TYPE_CHASSIS_ID = 1, + LLDP_TYPE_PORT_ID = 2, + LLDP_TYPE_TTL = 3, + LLDP_TYPE_PORT_DESCRIPTION = 4, + LLDP_TYPE_SYSTEM_NAME = 5, + LLDP_TYPE_SYSTEM_DESCRIPTION = 6, + LLDP_TYPE_SYSTEM_CAPABILITIES = 7, + LLDP_TYPE_MGMT_ADDRESS = 8, + LLDP_TYPE_PRIVATE = 127, + _LLDP_TYPE_MAX, + _LLDP_TYPE_INVALID = -1, +} LLDPTypes; + +/* IEEE 802.3AB Clause 9.5.2: Chassis subtypes */ +typedef enum LLDPChassisSubtypes { + LLDP_CHASSIS_SUBTYPE_RESERVED = 0, + LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT = 1, + LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS = 2, + LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT = 3, + LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS = 4, + LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5, + LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6, + LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7, + _LLDP_CHASSIS_SUBTYPE_MAX, + _LLDP_CHASSIS_SUBTYPE_INVALID = -1, +} LLDPChassisSubtypes; + +/* IEEE 802.3AB Clause 9.5.3: Port subtype */ +typedef enum LLDPPortSubtypes { + LLDP_PORT_SUBTYPE_RESERVED = 0, + LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1, + LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2, + LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3, + LLDP_PORT_SUBTYPE_NETWORK = 4, + LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5, + LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6, + LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7, + _LLDP_PORT_SUBTYPE_MAX, + _LLDP_PORT_SUBTYPE_INVALID = -1 +} LLDPPortSubtypes; + +typedef enum LLDPSystemCapabilities { + LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0, + LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1, + LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2, + LLDP_SYSTEM_CAPABILITIES_WLAN_AP = 1 << 3, + LLDP_SYSTEM_CAPABILITIES_ROUTER = 1 << 4, + LLDP_SYSTEM_CAPABILITIES_PHONE = 1 << 5, + LLDP_SYSTEM_CAPABILITIES_DOCSIS = 1 << 6, + LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7, + LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8, + LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9, + LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10, + _LLDP_SYSTEM_CAPABILITIES_MAX, + _LLDP_SYSTEM_CAPABILITIES_INVALID = -1, +} LLDPSystemCapabilities; + +typedef enum LLDPMedSubtype { + LLDP_MED_SUBTYPE_RESERVED = 0, + LLDP_MED_SUBTYPE_CAPABILITIES = 1, + LLDP_MED_SUBTYPE_NETWORK_POLICY = 2, + LLDP_MED_SUBTYPE_LOCATION_ID = 3, + LLDP_MED_SUBTYPE_EXTENDED_PVMDI = 4, + LLDP_MED_SUBTYPE_INV_HWREV = 5, + LLDP_MED_SUBTYPE_INV_FWREV = 6, + LLDP_MED_SUBTYPE_INV_SWREV = 7, + LLDP_MED_SUBTYPE_INV_SERIAL = 8, + LLDP_MED_SUBTYPE_INV_MANUFACTURER = 9, + LLDP_MED_SUBTYPE_INV_MODELNAME = 10, + LLDP_MED_SUBTYPE_INV_ASSETID = 11, + _LLDP_MED_SUBTYPE_MAX, + _LLDP_MED_SUBTYPE_INVALID = -1, +} LLDPMedSubtype; + +typedef enum LLDPMedCapability { + LLDP_MED_CAPABILITY_CAPAPILITIES = 1 << 0, + LLDP_MED_CAPABILITY_NETWORK_POLICY = 1 << 1, + LLDP_MED_CAPABILITY_LOCATION_ID = 1 << 2, + LLDP_MED_CAPABILITY_EXTENDED_PSE = 1 << 3, + LLDP_MED_CAPABILITY_EXTENDED_PD = 1 << 4, + LLDP_MED_CAPABILITY_INVENTORY = 1 << 5, + LLDP_MED_CAPABILITY_MAX, + LLDP_MED_CAPABILITY_INVALID = -1, +} LLDPMedCapability; + +#define LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 } +#define LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f } + +enum { + LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID = 1, + LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID = 2, + LLDP_OUI_SUBTYPE_802_1_VLAN_NAME = 3, + LLDP_OUI_SUBTYPE_802_1_PROTOCOL_IDENTITY = 4, + LLDP_OUI_SUBTYPE_802_1_VID_USAGE_DIGEST = 5, + LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID = 6, + LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION = 7, +}; diff --git a/src/systemd/src/libsystemd-network/network-internal.c b/src/systemd/src/libsystemd-network/network-internal.c new file mode 100644 index 00000000..579329c7 --- /dev/null +++ b/src/systemd/src/libsystemd-network/network-internal.c @@ -0,0 +1,560 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include + +#include "sd-ndisc.h" + +#include "alloc-util.h" +#if 0 /* NM_IGNORED */ +#include "condition.h" +#include "conf-parser.h" +#endif /* NM_IGNORED */ +#include "dhcp-lease-internal.h" +#include "hexdecoct.h" +#include "log.h" +#include "network-internal.h" +#include "parse-util.h" +#include "siphash24.h" +#include "string-util.h" +#include "strv.h" +#include "utf8.h" +#include "util.h" + +#if 0 /* NM_IGNORED */ +const char *net_get_name(struct udev_device *device) { + const char *name, *field; + + assert(device); + + /* fetch some persistent data unique (on this machine) to this device */ + FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") { + name = udev_device_get_property_value(device, field); + if (name) + return name; + } + + return NULL; +} + +#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a) + +int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result) { + size_t l, sz = 0; + const char *name = NULL; + int r; + uint8_t *v; + + assert(device); + + name = net_get_name(device); + if (!name) + return -ENOENT; + + l = strlen(name); + sz = sizeof(sd_id128_t) + l; + v = alloca(sz); + + /* fetch some persistent data unique to this machine */ + r = sd_id128_get_machine((sd_id128_t*) v); + if (r < 0) + return r; + memcpy(v + sizeof(sd_id128_t), name, l); + + /* Let's hash the machine ID plus the device name. We + * use a fixed, but originally randomly created hash + * key here. */ + *result = htole64(siphash24(v, sz, HASH_KEY.bytes)); + + return 0; +} + +bool net_match_config(const struct ether_addr *match_mac, + char * const *match_paths, + char * const *match_drivers, + char * const *match_types, + char * const *match_names, + Condition *match_host, + Condition *match_virt, + Condition *match_kernel, + Condition *match_arch, + const struct ether_addr *dev_mac, + const char *dev_path, + const char *dev_parent_driver, + const char *dev_driver, + const char *dev_type, + const char *dev_name) { + + if (match_host && !condition_test(match_host)) + return false; + + if (match_virt && !condition_test(match_virt)) + return false; + + if (match_kernel && !condition_test(match_kernel)) + return false; + + if (match_arch && !condition_test(match_arch)) + return false; + + if (match_mac && (!dev_mac || memcmp(match_mac, dev_mac, ETH_ALEN))) + return false; + + if (!strv_isempty(match_paths) && + (!dev_path || !strv_fnmatch(match_paths, dev_path, 0))) + return false; + + if (!strv_isempty(match_drivers) && + (!dev_driver || !strv_fnmatch(match_drivers, dev_driver, 0))) + return false; + + if (!strv_isempty(match_types) && + (!dev_type || !strv_fnmatch_or_empty(match_types, dev_type, 0))) + return false; + + if (!strv_isempty(match_names) && + (!dev_name || !strv_fnmatch_or_empty(match_names, dev_name, 0))) + return false; + + return true; +} + +int config_parse_net_condition(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + ConditionType cond = ltype; + Condition **ret = data; + bool negate; + Condition *c; + _cleanup_free_ char *s = NULL; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + negate = rvalue[0] == '!'; + if (negate) + rvalue++; + + s = strdup(rvalue); + if (!s) + return log_oom(); + + c = condition_new(cond, s, false, negate); + if (!c) + return log_oom(); + + if (*ret) + condition_free(*ret); + + *ret = c; + return 0; +} + +int config_parse_ifname(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char **s = data; + _cleanup_free_ char *n = NULL; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + n = strdup(rvalue); + if (!n) + return log_oom(); + + if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue); + return 0; + } + + free(*s); + if (*n) { + *s = n; + n = NULL; + } else + *s = NULL; + + return 0; +} + +int config_parse_ifnames(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char ***sv = data; + const char *word, *state; + size_t l; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + FOREACH_WORD(word, l, rvalue, state) { + char *n; + + n = strndup(word, l); + if (!n) + return log_oom(); + + if (!ascii_is_valid(n) || strlen(n) >= IFNAMSIZ) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Interface name is not ASCII clean or is too long, ignoring assignment: %s", rvalue); + free(n); + return 0; + } + + r = strv_consume(sv, n); + if (r < 0) + return log_oom(); + } + + return 0; +} + +int config_parse_ifalias(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char **s = data; + _cleanup_free_ char *n = NULL; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + n = strdup(rvalue); + if (!n) + return log_oom(); + + if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue); + return 0; + } + + free(*s); + if (*n) { + *s = n; + n = NULL; + } else + *s = NULL; + + return 0; +} + +int config_parse_hwaddr(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + struct ether_addr **hwaddr = data; + struct ether_addr *n; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + n = new0(struct ether_addr, 1); + if (!n) + return log_oom(); + + r = sscanf(rvalue, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + &n->ether_addr_octet[0], + &n->ether_addr_octet[1], + &n->ether_addr_octet[2], + &n->ether_addr_octet[3], + &n->ether_addr_octet[4], + &n->ether_addr_octet[5]); + if (r != 6) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring assignment: %s", rvalue); + free(n); + return 0; + } + + free(*hwaddr); + *hwaddr = n; + + return 0; +} +#endif /* NM_IGNORED */ + +void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) { + unsigned i; + + assert(f); + assert(addresses); + assert(size); + + for (i = 0; i < size; i++) + fprintf(f, "%s%s", inet_ntoa(addresses[i]), + (i < (size - 1)) ? " ": ""); +} + +int deserialize_in_addrs(struct in_addr **ret, const char *string) { + _cleanup_free_ struct in_addr *addresses = NULL; + int size = 0; + const char *word, *state; + size_t len; + + assert(ret); + assert(string); + + FOREACH_WORD(word, len, string, state) { + _cleanup_free_ char *addr_str = NULL; + struct in_addr *new_addresses; + int r; + + new_addresses = realloc(addresses, (size + 1) * sizeof(struct in_addr)); + if (!new_addresses) + return -ENOMEM; + else + addresses = new_addresses; + + addr_str = strndup(word, len); + if (!addr_str) + return -ENOMEM; + + r = inet_pton(AF_INET, addr_str, &(addresses[size])); + if (r <= 0) + continue; + + size ++; + } + + *ret = addresses; + addresses = NULL; + + return size; +} + +void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, + size_t size) { + unsigned i; + + assert(f); + assert(addresses); + assert(size); + + for (i = 0; i < size; i++) + fprintf(f, SD_NDISC_ADDRESS_FORMAT_STR"%s", + SD_NDISC_ADDRESS_FORMAT_VAL(addresses[i]), + (i < (size - 1)) ? " ": ""); +} + +int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { + _cleanup_free_ struct in6_addr *addresses = NULL; + int size = 0; + const char *word, *state; + size_t len; + + assert(ret); + assert(string); + + FOREACH_WORD(word, len, string, state) { + _cleanup_free_ char *addr_str = NULL; + struct in6_addr *new_addresses; + int r; + + new_addresses = realloc(addresses, (size + 1) * sizeof(struct in6_addr)); + if (!new_addresses) + return -ENOMEM; + else + addresses = new_addresses; + + addr_str = strndup(word, len); + if (!addr_str) + return -ENOMEM; + + r = inet_pton(AF_INET6, addr_str, &(addresses[size])); + if (r <= 0) + continue; + + size++; + } + + *ret = addresses; + addresses = NULL; + + return size; +} + +void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) { + unsigned i; + + assert(f); + assert(key); + assert(routes); + assert(size); + + fprintf(f, "%s=", key); + + for (i = 0; i < size; i++) { + fprintf(f, "%s/%" PRIu8, inet_ntoa(routes[i].dst_addr), + routes[i].dst_prefixlen); + fprintf(f, ",%s%s", inet_ntoa(routes[i].gw_addr), + (i < (size - 1)) ? " ": ""); + } + + fputs("\n", f); +} + +int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string) { + _cleanup_free_ struct sd_dhcp_route *routes = NULL; + size_t size = 0, allocated = 0; + const char *word, *state; + size_t len; + + assert(ret); + assert(ret_size); + assert(ret_allocated); + assert(string); + + FOREACH_WORD(word, len, string, state) { + /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */ + _cleanup_free_ char* entry = NULL; + char *tok, *tok_end; + unsigned n; + int r; + + if (!GREEDY_REALLOC(routes, allocated, size + 1)) + return -ENOMEM; + + entry = strndup(word, len); + if(!entry) + return -ENOMEM; + + tok = entry; + + /* get the subnet */ + tok_end = strchr(tok, '/'); + if (!tok_end) + continue; + *tok_end = '\0'; + + r = inet_aton(tok, &routes[size].dst_addr); + if (r == 0) + continue; + + tok = tok_end + 1; + + /* get the prefixlen */ + tok_end = strchr(tok, ','); + if (!tok_end) + continue; + + *tok_end = '\0'; + + r = safe_atou(tok, &n); + if (r < 0 || n > 32) + continue; + + routes[size].dst_prefixlen = (uint8_t) n; + tok = tok_end + 1; + + /* get the gateway */ + r = inet_aton(tok, &routes[size].gw_addr); + if (r == 0) + continue; + + size++; + } + + *ret_size = size; + *ret_allocated = allocated; + *ret = routes; + routes = NULL; + + return 0; +} + +int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) { + _cleanup_free_ char *hex_buf = NULL; + + assert(f); + assert(key); + assert(data); + + hex_buf = hexmem(data, size); + if (hex_buf == NULL) + return -ENOMEM; + + fprintf(f, "%s=%s\n", key, hex_buf); + + return 0; +} + +int deserialize_dhcp_option(void **data, size_t *data_len, const char *string) { + assert(data); + assert(data_len); + assert(string); + + if (strlen(string) % 2) + return -EINVAL; + + return unhexmem(string, strlen(string), (void **)data, data_len); +} diff --git a/src/systemd/src/libsystemd-network/network-internal.h b/src/systemd/src/libsystemd-network/network-internal.h new file mode 100644 index 00000000..17c2f4fb --- /dev/null +++ b/src/systemd/src/libsystemd-network/network-internal.h @@ -0,0 +1,85 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** + This file is part of systemd. + + Copyright (C) 2013 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include + +#if 0 /* NM_IGNORED */ +#include "condition.h" +#include "udev.h" + +bool net_match_config(const struct ether_addr *match_mac, + char * const *match_path, + char * const *match_driver, + char * const *match_type, + char * const *match_name, + Condition *match_host, + Condition *match_virt, + Condition *match_kernel, + Condition *match_arch, + const struct ether_addr *dev_mac, + const char *dev_path, + const char *dev_parent_driver, + const char *dev_driver, + const char *dev_type, + const char *dev_name); + +int config_parse_net_condition(const char *unit, const char *filename, unsigned line, + const char *section, unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata); + +int config_parse_hwaddr(const char *unit, const char *filename, unsigned line, + const char *section, unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata); + +int config_parse_ifname(const char *unit, const char *filename, unsigned line, + const char *section, unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata); + +int config_parse_ifnames(const char *unit, const char *filename, unsigned line, + const char *section, unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata); + +int config_parse_ifalias(const char *unit, const char *filename, unsigned line, + const char *section, unsigned section_line, const char *lvalue, + int ltype, const char *rvalue, void *data, void *userdata); + +int net_get_unique_predictable_data(struct udev_device *device, uint64_t *result); +const char *net_get_name(struct udev_device *device); +#endif /* NM_IGNORED */ + +void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size); +int deserialize_in_addrs(struct in_addr **addresses, const char *string); +void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, + size_t size); +int deserialize_in6_addrs(struct in6_addr **addresses, const char *string); + +/* don't include "dhcp-lease-internal.h" as it causes conflicts between netinet/ip.h and linux/ip.h */ +struct sd_dhcp_route; + +void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size); +int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string); + +int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size); +int deserialize_dhcp_option(void **data, size_t *data_len, const char *string); diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-client.c b/src/systemd/src/libsystemd-network/sd-dhcp-client.c new file mode 100644 index 00000000..23d2c4b0 --- /dev/null +++ b/src/systemd/src/libsystemd-network/sd-dhcp-client.c @@ -0,0 +1,1781 @@ +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd-dhcp-client.h" + +#include "alloc-util.h" +#include "async.h" +#include "dhcp-identifier.h" +#include "dhcp-internal.h" +#include "dhcp-lease-internal.h" +#include "dhcp-protocol.h" +#include "dns-domain.h" +#include "hostname-util.h" +#include "random-util.h" +#include "string-util.h" +#include "util.h" + +#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */ +#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN) + +struct sd_dhcp_client { + unsigned n_ref; + + DHCPState state; + sd_event *event; + int event_priority; + sd_event_source *timeout_resend; + int index; + int fd; + union sockaddr_union link; + sd_event_source *receive_message; + bool request_broadcast; + uint8_t *req_opts; + size_t req_opts_allocated; + size_t req_opts_size; + be32_t last_addr; + uint8_t mac_addr[MAX_MAC_ADDR_LEN]; + size_t mac_addr_len; + uint16_t arp_type; + struct { + uint8_t type; + union { + struct { + /* 0: Generic (non-LL) (RFC 2132) */ + uint8_t data[MAX_CLIENT_ID_LEN]; + } _packed_ gen; + struct { + /* 1: Ethernet Link-Layer (RFC 2132) */ + uint8_t haddr[ETH_ALEN]; + } _packed_ eth; + struct { + /* 2 - 254: ARP/Link-Layer (RFC 2132) */ + uint8_t haddr[0]; + } _packed_ ll; + struct { + /* 255: Node-specific (RFC 4361) */ + uint32_t iaid; + struct duid duid; + } _packed_ ns; + struct { + uint8_t data[MAX_CLIENT_ID_LEN]; + } _packed_ raw; + }; + } _packed_ client_id; + size_t client_id_len; + char *hostname; + char *vendor_class_identifier; + uint32_t mtu; + uint32_t xid; + usec_t start_time; + unsigned int attempt; + usec_t request_sent; + sd_event_source *timeout_t1; + sd_event_source *timeout_t2; + sd_event_source *timeout_expire; + sd_dhcp_client_cb_t cb; + void *userdata; + sd_dhcp_lease *lease; +}; + +static const uint8_t default_req_opts[] = { + DHCP_OPTION_SUBNET_MASK, + DHCP_OPTION_ROUTER, + DHCP_OPTION_HOST_NAME, + DHCP_OPTION_DOMAIN_NAME, + DHCP_OPTION_DOMAIN_NAME_SERVER, +}; + +static int client_receive_message_raw(sd_event_source *s, int fd, + uint32_t revents, void *userdata); +static int client_receive_message_udp(sd_event_source *s, int fd, + uint32_t revents, void *userdata); +static void client_stop(sd_dhcp_client *client, int error); + +int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb, + void *userdata) { + assert_return(client, -EINVAL); + + client->cb = cb; + client->userdata = userdata; + + return 0; +} + +int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) { + assert_return(client, -EINVAL); + + client->request_broadcast = !!broadcast; + + return 0; +} + +int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) { + size_t i; + + assert_return(client, -EINVAL); + assert_return (IN_SET(client->state, DHCP_STATE_INIT, + DHCP_STATE_STOPPED), -EBUSY); + + switch(option) { + case DHCP_OPTION_PAD: + case DHCP_OPTION_OVERLOAD: + case DHCP_OPTION_MESSAGE_TYPE: + case DHCP_OPTION_PARAMETER_REQUEST_LIST: + case DHCP_OPTION_END: + return -EINVAL; + + default: + break; + } + + for (i = 0; i < client->req_opts_size; i++) + if (client->req_opts[i] == option) + return -EEXIST; + + if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated, + client->req_opts_size + 1)) + return -ENOMEM; + + client->req_opts[client->req_opts_size++] = option; + + return 0; +} + +int sd_dhcp_client_set_request_address(sd_dhcp_client *client, + const struct in_addr *last_addr) { + assert_return(client, -EINVAL); + assert_return (IN_SET(client->state, DHCP_STATE_INIT, + DHCP_STATE_STOPPED), -EBUSY); + + if (last_addr) + client->last_addr = last_addr->s_addr; + else + client->last_addr = INADDR_ANY; + + return 0; +} + +int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index) { + assert_return(client, -EINVAL); + assert_return (IN_SET(client->state, DHCP_STATE_INIT, + DHCP_STATE_STOPPED), -EBUSY); + assert_return(interface_index > 0, -EINVAL); + + client->index = interface_index; + + return 0; +} + +int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, + size_t addr_len, uint16_t arp_type) { + DHCP_CLIENT_DONT_DESTROY(client); + bool need_restart = false; + + assert_return(client, -EINVAL); + assert_return(addr, -EINVAL); + assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL); + assert_return(arp_type > 0, -EINVAL); + + if (arp_type == ARPHRD_ETHER) + assert_return(addr_len == ETH_ALEN, -EINVAL); + else if (arp_type == ARPHRD_INFINIBAND) + assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + else + return -EINVAL; + + if (client->mac_addr_len == addr_len && + memcmp(&client->mac_addr, addr, addr_len) == 0) + return 0; + + if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { + log_dhcp_client(client, "Changing MAC address on running DHCP " + "client, restarting"); + need_restart = true; + client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); + } + + memcpy(&client->mac_addr, addr, addr_len); + client->mac_addr_len = addr_len; + client->arp_type = arp_type; + + if (need_restart && client->state != DHCP_STATE_STOPPED) + sd_dhcp_client_start(client); + + return 0; +} + +int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, + const uint8_t **data, size_t *data_len) { + + assert_return(client, -EINVAL); + assert_return(type, -EINVAL); + assert_return(data, -EINVAL); + assert_return(data_len, -EINVAL); + + *type = 0; + *data = NULL; + *data_len = 0; + if (client->client_id_len) { + *type = client->client_id.type; + *data = client->client_id.raw.data; + *data_len = client->client_id_len - sizeof(client->client_id.type); + } + + return 0; +} + +int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, + const uint8_t *data, size_t data_len) { + DHCP_CLIENT_DONT_DESTROY(client); + bool need_restart = false; + + assert_return(client, -EINVAL); + assert_return(data, -EINVAL); + assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL); + + switch (type) { + case ARPHRD_ETHER: + if (data_len != ETH_ALEN) + return -EINVAL; + break; + case ARPHRD_INFINIBAND: + if (data_len != INFINIBAND_ALEN) + return -EINVAL; + break; + default: + break; + } + + if (client->client_id_len == data_len + sizeof(client->client_id.type) && + client->client_id.type == type && + memcmp(&client->client_id.raw.data, data, data_len) == 0) + return 0; + + if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { + log_dhcp_client(client, "Changing client ID on running DHCP " + "client, restarting"); + need_restart = true; + client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); + } + + client->client_id.type = type; + memcpy(&client->client_id.raw.data, data, data_len); + client->client_id_len = data_len + sizeof (client->client_id.type); + + if (need_restart && client->state != DHCP_STATE_STOPPED) + sd_dhcp_client_start(client); + + return 0; +} + +int sd_dhcp_client_set_hostname(sd_dhcp_client *client, + const char *hostname) { + char *new_hostname = NULL; + + assert_return(client, -EINVAL); + + if (!hostname_is_valid(hostname, false) && !dns_name_is_valid(hostname)) + return -EINVAL; + + if (streq_ptr(client->hostname, hostname)) + return 0; + + if (hostname) { + new_hostname = strdup(hostname); + if (!new_hostname) + return -ENOMEM; + } + + free(client->hostname); + client->hostname = new_hostname; + + return 0; +} + +int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, + const char *vci) { + char *new_vci = NULL; + + assert_return(client, -EINVAL); + + new_vci = strdup(vci); + if (!new_vci) + return -ENOMEM; + + free(client->vendor_class_identifier); + + client->vendor_class_identifier = new_vci; + + return 0; +} + +int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) { + assert_return(client, -EINVAL); + assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE); + + client->mtu = mtu; + + return 0; +} + +int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { + assert_return(client, -EINVAL); + assert_return(ret, -EINVAL); + + if (client->state != DHCP_STATE_BOUND && + client->state != DHCP_STATE_RENEWING && + client->state != DHCP_STATE_REBINDING) + return -EADDRNOTAVAIL; + + *ret = client->lease; + + return 0; +} + +static void client_notify(sd_dhcp_client *client, int event) { + if (client->cb) + client->cb(client, event, client->userdata); +} + +static int client_initialize(sd_dhcp_client *client) { + assert_return(client, -EINVAL); + + client->receive_message = + sd_event_source_unref(client->receive_message); + + client->fd = asynchronous_close(client->fd); + + client->timeout_resend = sd_event_source_unref(client->timeout_resend); + + client->timeout_t1 = sd_event_source_unref(client->timeout_t1); + client->timeout_t2 = sd_event_source_unref(client->timeout_t2); + client->timeout_expire = sd_event_source_unref(client->timeout_expire); + + client->attempt = 1; + + client->state = DHCP_STATE_INIT; + client->xid = 0; + + client->lease = sd_dhcp_lease_unref(client->lease); + + return 0; +} + +static void client_stop(sd_dhcp_client *client, int error) { + assert(client); + + if (error < 0) + log_dhcp_client(client, "STOPPED: %s", strerror(-error)); + else if (error == SD_DHCP_CLIENT_EVENT_STOP) + log_dhcp_client(client, "STOPPED"); + else + log_dhcp_client(client, "STOPPED: Unknown event"); + + client_notify(client, error); + + client_initialize(client); +} + +static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, + uint8_t type, size_t *_optlen, size_t *_optoffset) { + _cleanup_free_ DHCPPacket *packet = NULL; + size_t optlen, optoffset, size; + be16_t max_size; + usec_t time_now; + uint16_t secs; + int r; + + assert(client); + assert(client->start_time); + assert(ret); + assert(_optlen); + assert(_optoffset); + assert(type == DHCP_DISCOVER || type == DHCP_REQUEST); + + optlen = DHCP_MIN_OPTIONS_SIZE; + size = sizeof(DHCPPacket) + optlen; + + packet = malloc0(size); + if (!packet) + return -ENOMEM; + + r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type, + client->arp_type, optlen, &optoffset); + if (r < 0) + return r; + + /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers + refuse to issue an DHCP lease if 'secs' is set to zero */ + r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); + if (r < 0) + return r; + assert(time_now >= client->start_time); + + /* seconds between sending first and last DISCOVER + * must always be strictly positive to deal with broken servers */ + secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1; + packet->dhcp.secs = htobe16(secs); + + /* RFC2132 section 4.1 + A client that cannot receive unicast IP datagrams until its protocol + software has been configured with an IP address SHOULD set the + BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or + DHCPREQUEST messages that client sends. The BROADCAST bit will + provide a hint to the DHCP server and BOOTP relay agent to broadcast + any messages to the client on the client's subnet. + + Note: some interfaces needs this to be enabled, but some networks + needs this to be disabled as broadcasts are filteretd, so this + needs to be configurable */ + if (client->request_broadcast || client->arp_type != ARPHRD_ETHER) + packet->dhcp.flags = htobe16(0x8000); + + /* RFC2132 section 4.1.1: + The client MUST include its hardware address in the ’chaddr’ field, if + necessary for delivery of DHCP reply messages. Non-Ethernet + interfaces will leave 'chaddr' empty and use the client identifier + instead (eg, RFC 4390 section 2.1). + */ + if (client->arp_type == ARPHRD_ETHER) + memcpy(&packet->dhcp.chaddr, &client->mac_addr, ETH_ALEN); + + /* If no client identifier exists, construct an RFC 4361-compliant one */ + if (client->client_id_len == 0) { + size_t duid_len; + + client->client_id.type = 255; + + r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->client_id.ns.iaid); + if (r < 0) + return r; + + r = dhcp_identifier_set_duid_en(&client->client_id.ns.duid, &duid_len); + if (r < 0) + return r; + + client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len; + } + + /* Some DHCP servers will refuse to issue an DHCP lease if the Client + Identifier option is not set */ + if (client->client_id_len) { + r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, + DHCP_OPTION_CLIENT_IDENTIFIER, + client->client_id_len, + &client->client_id); + if (r < 0) + return r; + } + + /* RFC2131 section 3.5: + in its initial DHCPDISCOVER or DHCPREQUEST message, a + client may provide the server with a list of specific + parameters the client is interested in. If the client + includes a list of parameters in a DHCPDISCOVER message, + it MUST include that list in any subsequent DHCPREQUEST + messages. + */ + r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, + DHCP_OPTION_PARAMETER_REQUEST_LIST, + client->req_opts_size, client->req_opts); + if (r < 0) + return r; + + /* RFC2131 section 3.5: + The client SHOULD include the ’maximum DHCP message size’ option to + let the server know how large the server may make its DHCP messages. + + Note (from ConnMan): Some DHCP servers will send bigger DHCP packets + than the defined default size unless the Maximum Messge Size option + is explicitly set + + RFC3442 "Requirements to Avoid Sizing Constraints": + Because a full routing table can be quite large, the standard 576 + octet maximum size for a DHCP message may be too short to contain + some legitimate Classless Static Route options. Because of this, + clients implementing the Classless Static Route option SHOULD send a + Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP + stack is capable of receiving larger IP datagrams. In this case, the + client SHOULD set the value of this option to at least the MTU of the + interface that the client is configuring. The client MAY set the + value of this option higher, up to the size of the largest UDP packet + it is prepared to accept. (Note that the value specified in the + Maximum DHCP Message Size option is the total maximum packet size, + including IP and UDP headers.) + */ + max_size = htobe16(size); + r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0, + DHCP_OPTION_MAXIMUM_MESSAGE_SIZE, + 2, &max_size); + if (r < 0) + return r; + + *_optlen = optlen; + *_optoffset = optoffset; + *ret = packet; + packet = NULL; + + return 0; +} + +static int client_append_fqdn_option(DHCPMessage *message, size_t optlen, size_t *optoffset, + const char *fqdn) { + uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH]; + int r; + + buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */ + DHCP_FQDN_FLAG_E; /* Canonical wire format */ + buffer[1] = 0; /* RCODE1 (deprecated) */ + buffer[2] = 0; /* RCODE2 (deprecated) */ + + r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3, false); + if (r > 0) + r = dhcp_option_append(message, optlen, optoffset, 0, + DHCP_OPTION_FQDN, 3 + r, buffer); + + return r; +} + +static int dhcp_client_send_raw(sd_dhcp_client *client, DHCPPacket *packet, + size_t len) { + dhcp_packet_append_ip_headers(packet, INADDR_ANY, DHCP_PORT_CLIENT, + INADDR_BROADCAST, DHCP_PORT_SERVER, len); + + return dhcp_network_send_raw_socket(client->fd, &client->link, + packet, len); +} + +static int client_send_discover(sd_dhcp_client *client) { + _cleanup_free_ DHCPPacket *discover = NULL; + size_t optoffset, optlen; + int r; + + assert(client); + assert(client->state == DHCP_STATE_INIT || + client->state == DHCP_STATE_SELECTING); + + r = client_message_init(client, &discover, DHCP_DISCOVER, + &optlen, &optoffset); + if (r < 0) + return r; + + /* the client may suggest values for the network address + and lease time in the DHCPDISCOVER message. The client may include + the ’requested IP address’ option to suggest that a particular IP + address be assigned, and may include the ’IP address lease time’ + option to suggest the lease time it would like. + */ + if (client->last_addr != INADDR_ANY) { + r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, + DHCP_OPTION_REQUESTED_IP_ADDRESS, + 4, &client->last_addr); + if (r < 0) + return r; + } + + if (client->hostname) { + /* According to RFC 4702 "clients that send the Client FQDN option in + their messages MUST NOT also send the Host Name option". Just send + one of the two depending on the hostname type. + */ + if (dns_name_is_single_label(client->hostname)) { + /* it is unclear from RFC 2131 if client should send hostname in + DHCPDISCOVER but dhclient does and so we do as well + */ + r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, + DHCP_OPTION_HOST_NAME, + strlen(client->hostname), client->hostname); + } else + r = client_append_fqdn_option(&discover->dhcp, optlen, &optoffset, + client->hostname); + if (r < 0) + return r; + } + + if (client->vendor_class_identifier) { + r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, + DHCP_OPTION_VENDOR_CLASS_IDENTIFIER, + strlen(client->vendor_class_identifier), + client->vendor_class_identifier); + if (r < 0) + return r; + } + + r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, + DHCP_OPTION_END, 0, NULL); + if (r < 0) + return r; + + /* We currently ignore: + The client SHOULD wait a random time between one and ten seconds to + desynchronize the use of DHCP at startup. + */ + r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset); + if (r < 0) + return r; + + log_dhcp_client(client, "DISCOVER"); + + return 0; +} + +static int client_send_request(sd_dhcp_client *client) { + _cleanup_free_ DHCPPacket *request = NULL; + size_t optoffset, optlen; + int r; + + r = client_message_init(client, &request, DHCP_REQUEST, + &optlen, &optoffset); + if (r < 0) + return r; + + switch (client->state) { + /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC, + SELECTING should be REQUESTING) + */ + + case DHCP_STATE_REQUESTING: + /* Client inserts the address of the selected server in ’server + identifier’, ’ciaddr’ MUST be zero, ’requested IP address’ MUST be + filled in with the yiaddr value from the chosen DHCPOFFER. + */ + + r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, + DHCP_OPTION_SERVER_IDENTIFIER, + 4, &client->lease->server_address); + if (r < 0) + return r; + + r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, + DHCP_OPTION_REQUESTED_IP_ADDRESS, + 4, &client->lease->address); + if (r < 0) + return r; + + break; + + case DHCP_STATE_INIT_REBOOT: + /* ’server identifier’ MUST NOT be filled in, ’requested IP address’ + option MUST be filled in with client’s notion of its previously + assigned address. ’ciaddr’ MUST be zero. + */ + r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, + DHCP_OPTION_REQUESTED_IP_ADDRESS, + 4, &client->last_addr); + if (r < 0) + return r; + break; + + case DHCP_STATE_RENEWING: + /* ’server identifier’ MUST NOT be filled in, ’requested IP address’ + option MUST NOT be filled in, ’ciaddr’ MUST be filled in with + client’s IP address. + */ + + /* fall through */ + case DHCP_STATE_REBINDING: + /* ’server identifier’ MUST NOT be filled in, ’requested IP address’ + option MUST NOT be filled in, ’ciaddr’ MUST be filled in with + client’s IP address. + + This message MUST be broadcast to the 0xffffffff IP broadcast address. + */ + request->dhcp.ciaddr = client->lease->address; + + break; + + case DHCP_STATE_INIT: + case DHCP_STATE_SELECTING: + case DHCP_STATE_REBOOTING: + case DHCP_STATE_BOUND: + case DHCP_STATE_STOPPED: + return -EINVAL; + } + + if (client->hostname) { + if (dns_name_is_single_label(client->hostname)) + r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, + DHCP_OPTION_HOST_NAME, + strlen(client->hostname), client->hostname); + else + r = client_append_fqdn_option(&request->dhcp, optlen, &optoffset, + client->hostname); + if (r < 0) + return r; + } + + r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, + DHCP_OPTION_END, 0, NULL); + if (r < 0) + return r; + + if (client->state == DHCP_STATE_RENEWING) { + r = dhcp_network_send_udp_socket(client->fd, + client->lease->server_address, + DHCP_PORT_SERVER, + &request->dhcp, + sizeof(DHCPMessage) + optoffset); + } else { + r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset); + } + if (r < 0) + return r; + + switch (client->state) { + case DHCP_STATE_REQUESTING: + log_dhcp_client(client, "REQUEST (requesting)"); + break; + case DHCP_STATE_INIT_REBOOT: + log_dhcp_client(client, "REQUEST (init-reboot)"); + break; + case DHCP_STATE_RENEWING: + log_dhcp_client(client, "REQUEST (renewing)"); + break; + case DHCP_STATE_REBINDING: + log_dhcp_client(client, "REQUEST (rebinding)"); + break; + default: + log_dhcp_client(client, "REQUEST (invalid)"); + break; + } + + return 0; +} + +static int client_start(sd_dhcp_client *client); + +static int client_timeout_resend(sd_event_source *s, uint64_t usec, + void *userdata) { + sd_dhcp_client *client = userdata; + DHCP_CLIENT_DONT_DESTROY(client); + usec_t next_timeout = 0; + uint64_t time_now; + uint32_t time_left; + int r; + + assert(s); + assert(client); + assert(client->event); + + r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); + if (r < 0) + goto error; + + switch (client->state) { + case DHCP_STATE_RENEWING: + + time_left = (client->lease->t2 - client->lease->t1) / 2; + if (time_left < 60) + time_left = 60; + + next_timeout = time_now + time_left * USEC_PER_SEC; + + break; + + case DHCP_STATE_REBINDING: + + time_left = (client->lease->lifetime - client->lease->t2) / 2; + if (time_left < 60) + time_left = 60; + + next_timeout = time_now + time_left * USEC_PER_SEC; + break; + + case DHCP_STATE_REBOOTING: + /* start over as we did not receive a timely ack or nak */ + r = client_initialize(client); + if (r < 0) + goto error; + + r = client_start(client); + if (r < 0) + goto error; + else { + log_dhcp_client(client, "REBOOTED"); + return 0; + } + + case DHCP_STATE_INIT: + case DHCP_STATE_INIT_REBOOT: + case DHCP_STATE_SELECTING: + case DHCP_STATE_REQUESTING: + case DHCP_STATE_BOUND: + + if (client->attempt < 64) + client->attempt *= 2; + + next_timeout = time_now + (client->attempt - 1) * USEC_PER_SEC; + + break; + + case DHCP_STATE_STOPPED: + r = -EINVAL; + goto error; + } + + next_timeout += (random_u32() & 0x1fffff); + + client->timeout_resend = sd_event_source_unref(client->timeout_resend); + + r = sd_event_add_time(client->event, + &client->timeout_resend, + clock_boottime_or_monotonic(), + next_timeout, 10 * USEC_PER_MSEC, + client_timeout_resend, client); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(client->timeout_resend, + client->event_priority); + if (r < 0) + goto error; + + r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); + if (r < 0) + goto error; + + switch (client->state) { + case DHCP_STATE_INIT: + r = client_send_discover(client); + if (r >= 0) { + client->state = DHCP_STATE_SELECTING; + client->attempt = 1; + } else { + if (client->attempt >= 64) + goto error; + } + + break; + + case DHCP_STATE_SELECTING: + r = client_send_discover(client); + if (r < 0 && client->attempt >= 64) + goto error; + + break; + + case DHCP_STATE_INIT_REBOOT: + case DHCP_STATE_REQUESTING: + case DHCP_STATE_RENEWING: + case DHCP_STATE_REBINDING: + r = client_send_request(client); + if (r < 0 && client->attempt >= 64) + goto error; + + if (client->state == DHCP_STATE_INIT_REBOOT) + client->state = DHCP_STATE_REBOOTING; + + client->request_sent = time_now; + + break; + + case DHCP_STATE_REBOOTING: + case DHCP_STATE_BOUND: + + break; + + case DHCP_STATE_STOPPED: + r = -EINVAL; + goto error; + } + + return 0; + +error: + client_stop(client, r); + + /* Errors were dealt with when stopping the client, don't spill + errors into the event loop handler */ + return 0; +} + +static int client_initialize_io_events(sd_dhcp_client *client, + sd_event_io_handler_t io_callback) { + int r; + + assert(client); + assert(client->event); + + r = sd_event_add_io(client->event, &client->receive_message, + client->fd, EPOLLIN, io_callback, + client); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(client->receive_message, + client->event_priority); + if (r < 0) + goto error; + + r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message"); + if (r < 0) + goto error; + +error: + if (r < 0) + client_stop(client, r); + + return 0; +} + +static int client_initialize_time_events(sd_dhcp_client *client) { + int r; + + assert(client); + assert(client->event); + + client->timeout_resend = sd_event_source_unref(client->timeout_resend); + + r = sd_event_add_time(client->event, + &client->timeout_resend, + clock_boottime_or_monotonic(), + 0, 0, + client_timeout_resend, client); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(client->timeout_resend, + client->event_priority); + if (r < 0) + goto error; + + r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); + if (r < 0) + goto error; + +error: + if (r < 0) + client_stop(client, r); + + return 0; + +} + +static int client_initialize_events(sd_dhcp_client *client, + sd_event_io_handler_t io_callback) { + client_initialize_io_events(client, io_callback); + client_initialize_time_events(client); + + return 0; +} + +static int client_start(sd_dhcp_client *client) { + int r; + + assert_return(client, -EINVAL); + assert_return(client->event, -EINVAL); + assert_return(client->index > 0, -EINVAL); + assert_return(client->fd < 0, -EBUSY); + assert_return(client->xid == 0, -EINVAL); + assert_return(client->state == DHCP_STATE_INIT || + client->state == DHCP_STATE_INIT_REBOOT, -EBUSY); + + client->xid = random_u32(); + + r = dhcp_network_bind_raw_socket(client->index, &client->link, + client->xid, client->mac_addr, + client->mac_addr_len, client->arp_type); + if (r < 0) { + client_stop(client, r); + return r; + } + client->fd = r; + + if (client->state == DHCP_STATE_INIT || client->state == DHCP_STATE_INIT_REBOOT) + client->start_time = now(clock_boottime_or_monotonic()); + + return client_initialize_events(client, client_receive_message_raw); +} + +static int client_timeout_expire(sd_event_source *s, uint64_t usec, + void *userdata) { + sd_dhcp_client *client = userdata; + DHCP_CLIENT_DONT_DESTROY(client); + + log_dhcp_client(client, "EXPIRED"); + + client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED); + + /* lease was lost, start over if not freed or stopped in callback */ + if (client->state != DHCP_STATE_STOPPED) { + client_initialize(client); + client_start(client); + } + + return 0; +} + +static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) { + sd_dhcp_client *client = userdata; + DHCP_CLIENT_DONT_DESTROY(client); + int r; + + client->receive_message = sd_event_source_unref(client->receive_message); + client->fd = asynchronous_close(client->fd); + + client->state = DHCP_STATE_REBINDING; + client->attempt = 1; + + r = dhcp_network_bind_raw_socket(client->index, &client->link, + client->xid, client->mac_addr, + client->mac_addr_len, client->arp_type); + if (r < 0) { + client_stop(client, r); + return 0; + } + client->fd = r; + + return client_initialize_events(client, client_receive_message_raw); +} + +static int client_timeout_t1(sd_event_source *s, uint64_t usec, + void *userdata) { + sd_dhcp_client *client = userdata; + DHCP_CLIENT_DONT_DESTROY(client); + + client->state = DHCP_STATE_RENEWING; + client->attempt = 1; + + return client_initialize_time_events(client); +} + +static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, + size_t len) { + _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; + int r; + + r = dhcp_lease_new(&lease); + if (r < 0) + return r; + + if (client->client_id_len) { + r = dhcp_lease_set_client_id(lease, + (uint8_t *) &client->client_id, + client->client_id_len); + if (r < 0) + return r; + } + + r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL); + if (r != DHCP_OFFER) { + log_dhcp_client(client, "received message was not an OFFER, ignoring"); + return -ENOMSG; + } + + lease->next_server = offer->siaddr; + lease->address = offer->yiaddr; + + if (lease->address == 0 || + lease->server_address == 0 || + lease->lifetime == 0) { + log_dhcp_client(client, "received lease lacks address, server address or lease lifetime, ignoring"); + return -ENOMSG; + } + + if (!lease->have_subnet_mask) { + r = dhcp_lease_set_default_subnet_mask(lease); + if (r < 0) { + log_dhcp_client(client, "received lease lacks subnet " + "mask, and a fallback one can not be " + "generated, ignoring"); + return -ENOMSG; + } + } + + sd_dhcp_lease_unref(client->lease); + client->lease = lease; + lease = NULL; + + log_dhcp_client(client, "OFFER"); + + return 0; +} + +static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, + size_t len) { + int r; + + r = dhcp_option_parse(force, len, NULL, NULL, NULL); + if (r != DHCP_FORCERENEW) + return -ENOMSG; + + log_dhcp_client(client, "FORCERENEW"); + + return 0; +} + +static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, + size_t len) { + _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; + _cleanup_free_ char *error_message = NULL; + int r; + + r = dhcp_lease_new(&lease); + if (r < 0) + return r; + + if (client->client_id_len) { + r = dhcp_lease_set_client_id(lease, + (uint8_t *) &client->client_id, + client->client_id_len); + if (r < 0) + return r; + } + + r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message); + if (r == DHCP_NAK) { + log_dhcp_client(client, "NAK: %s", strna(error_message)); + return -EADDRNOTAVAIL; + } + + if (r != DHCP_ACK) { + log_dhcp_client(client, "received message was not an ACK, ignoring"); + return -ENOMSG; + } + + lease->next_server = ack->siaddr; + + lease->address = ack->yiaddr; + + if (lease->address == INADDR_ANY || + lease->server_address == INADDR_ANY || + lease->lifetime == 0) { + log_dhcp_client(client, "received lease lacks address, server " + "address or lease lifetime, ignoring"); + return -ENOMSG; + } + + if (lease->subnet_mask == INADDR_ANY) { + r = dhcp_lease_set_default_subnet_mask(lease); + if (r < 0) { + log_dhcp_client(client, "received lease lacks subnet " + "mask, and a fallback one can not be " + "generated, ignoring"); + return -ENOMSG; + } + } + + r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE; + if (client->lease) { + if (client->lease->address != lease->address || + client->lease->subnet_mask != lease->subnet_mask || + client->lease->router != lease->router) { + r = SD_DHCP_CLIENT_EVENT_IP_CHANGE; + } else + r = SD_DHCP_CLIENT_EVENT_RENEW; + + client->lease = sd_dhcp_lease_unref(client->lease); + } + + client->lease = lease; + lease = NULL; + + log_dhcp_client(client, "ACK"); + + return r; +} + +static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) { + assert(client); + assert(client->request_sent); + assert(lifetime > 0); + + if (lifetime > 3) + lifetime -= 3; + else + lifetime = 0; + + return client->request_sent + (lifetime * USEC_PER_SEC * factor) + + + (random_u32() & 0x1fffff); +} + +static int client_set_lease_timeouts(sd_dhcp_client *client) { + usec_t time_now; + uint64_t lifetime_timeout; + uint64_t t2_timeout; + uint64_t t1_timeout; + char time_string[FORMAT_TIMESPAN_MAX]; + int r; + + assert(client); + assert(client->event); + assert(client->lease); + assert(client->lease->lifetime); + + client->timeout_t1 = sd_event_source_unref(client->timeout_t1); + client->timeout_t2 = sd_event_source_unref(client->timeout_t2); + client->timeout_expire = sd_event_source_unref(client->timeout_expire); + + /* don't set timers for infinite leases */ + if (client->lease->lifetime == 0xffffffff) + return 0; + + r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); + if (r < 0) + return r; + assert(client->request_sent <= time_now); + + /* convert the various timeouts from relative (secs) to absolute (usecs) */ + lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1); + if (client->lease->t1 > 0 && client->lease->t2 > 0) { + /* both T1 and T2 are given */ + if (client->lease->t1 < client->lease->t2 && + client->lease->t2 < client->lease->lifetime) { + /* they are both valid */ + t2_timeout = client_compute_timeout(client, client->lease->t2, 1); + t1_timeout = client_compute_timeout(client, client->lease->t1, 1); + } else { + /* discard both */ + t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); + client->lease->t2 = (client->lease->lifetime * 7) / 8; + t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); + client->lease->t1 = client->lease->lifetime / 2; + } + } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) { + /* only T2 is given, and it is valid */ + t2_timeout = client_compute_timeout(client, client->lease->t2, 1); + t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); + client->lease->t1 = client->lease->lifetime / 2; + if (t2_timeout <= t1_timeout) { + /* the computed T1 would be invalid, so discard T2 */ + t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); + client->lease->t2 = (client->lease->lifetime * 7) / 8; + } + } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) { + /* only T1 is given, and it is valid */ + t1_timeout = client_compute_timeout(client, client->lease->t1, 1); + t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); + client->lease->t2 = (client->lease->lifetime * 7) / 8; + if (t2_timeout <= t1_timeout) { + /* the computed T2 would be invalid, so discard T1 */ + t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); + client->lease->t2 = client->lease->lifetime / 2; + } + } else { + /* fall back to the default timeouts */ + t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); + client->lease->t1 = client->lease->lifetime / 2; + t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); + client->lease->t2 = (client->lease->lifetime * 7) / 8; + } + + /* arm lifetime timeout */ + r = sd_event_add_time(client->event, &client->timeout_expire, + clock_boottime_or_monotonic(), + lifetime_timeout, 10 * USEC_PER_MSEC, + client_timeout_expire, client); + if (r < 0) + return r; + + r = sd_event_source_set_priority(client->timeout_expire, + client->event_priority); + if (r < 0) + return r; + + r = sd_event_source_set_description(client->timeout_expire, "dhcp4-lifetime"); + if (r < 0) + return r; + + log_dhcp_client(client, "lease expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC)); + + /* don't arm earlier timeouts if this has already expired */ + if (lifetime_timeout <= time_now) + return 0; + + /* arm T2 timeout */ + r = sd_event_add_time(client->event, + &client->timeout_t2, + clock_boottime_or_monotonic(), + t2_timeout, + 10 * USEC_PER_MSEC, + client_timeout_t2, client); + if (r < 0) + return r; + + r = sd_event_source_set_priority(client->timeout_t2, + client->event_priority); + if (r < 0) + return r; + + r = sd_event_source_set_description(client->timeout_t2, "dhcp4-t2-timeout"); + if (r < 0) + return r; + + log_dhcp_client(client, "T2 expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC)); + + /* don't arm earlier timeout if this has already expired */ + if (t2_timeout <= time_now) + return 0; + + /* arm T1 timeout */ + r = sd_event_add_time(client->event, + &client->timeout_t1, + clock_boottime_or_monotonic(), + t1_timeout, 10 * USEC_PER_MSEC, + client_timeout_t1, client); + if (r < 0) + return r; + + r = sd_event_source_set_priority(client->timeout_t1, + client->event_priority); + if (r < 0) + return r; + + r = sd_event_source_set_description(client->timeout_t1, "dhcp4-t1-timer"); + if (r < 0) + return r; + + log_dhcp_client(client, "T1 expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC)); + + return 0; +} + +static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, + int len) { + DHCP_CLIENT_DONT_DESTROY(client); + int r = 0, notify_event = 0; + + assert(client); + assert(client->event); + assert(message); + + switch (client->state) { + case DHCP_STATE_SELECTING: + + r = client_handle_offer(client, message, len); + if (r >= 0) { + + client->timeout_resend = + sd_event_source_unref(client->timeout_resend); + + client->state = DHCP_STATE_REQUESTING; + client->attempt = 1; + + r = sd_event_add_time(client->event, + &client->timeout_resend, + clock_boottime_or_monotonic(), + 0, 0, + client_timeout_resend, client); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(client->timeout_resend, + client->event_priority); + if (r < 0) + goto error; + + r = sd_event_source_set_description(client->timeout_resend, "dhcp4-resend-timer"); + if (r < 0) + goto error; + } else if (r == -ENOMSG) + /* invalid message, let's ignore it */ + return 0; + + break; + + case DHCP_STATE_REBOOTING: + case DHCP_STATE_REQUESTING: + case DHCP_STATE_RENEWING: + case DHCP_STATE_REBINDING: + + r = client_handle_ack(client, message, len); + if (r >= 0) { + client->timeout_resend = + sd_event_source_unref(client->timeout_resend); + client->receive_message = + sd_event_source_unref(client->receive_message); + client->fd = asynchronous_close(client->fd); + + if (IN_SET(client->state, DHCP_STATE_REQUESTING, + DHCP_STATE_REBOOTING)) + notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE; + else if (r != SD_DHCP_CLIENT_EVENT_IP_ACQUIRE) + notify_event = r; + + client->state = DHCP_STATE_BOUND; + client->attempt = 1; + + client->last_addr = client->lease->address; + + r = client_set_lease_timeouts(client); + if (r < 0) { + log_dhcp_client(client, "could not set lease timeouts"); + goto error; + } + + r = dhcp_network_bind_udp_socket(client->lease->address, + DHCP_PORT_CLIENT); + if (r < 0) { + log_dhcp_client(client, "could not bind UDP socket"); + goto error; + } + + client->fd = r; + + client_initialize_io_events(client, client_receive_message_udp); + + if (notify_event) { + client_notify(client, notify_event); + if (client->state == DHCP_STATE_STOPPED) + return 0; + } + + } else if (r == -EADDRNOTAVAIL) { + /* got a NAK, let's restart the client */ + client->timeout_resend = + sd_event_source_unref(client->timeout_resend); + + r = client_initialize(client); + if (r < 0) + goto error; + + r = client_start(client); + if (r < 0) + goto error; + + log_dhcp_client(client, "REBOOTED"); + + return 0; + } else if (r == -ENOMSG) + /* invalid message, let's ignore it */ + return 0; + + break; + + case DHCP_STATE_BOUND: + r = client_handle_forcerenew(client, message, len); + if (r >= 0) { + r = client_timeout_t1(NULL, 0, client); + if (r < 0) + goto error; + } else if (r == -ENOMSG) + /* invalid message, let's ignore it */ + return 0; + + break; + + case DHCP_STATE_INIT: + case DHCP_STATE_INIT_REBOOT: + + break; + + case DHCP_STATE_STOPPED: + r = -EINVAL; + goto error; + } + +error: + if (r < 0) + client_stop(client, r); + + return r; +} + +static int client_receive_message_udp(sd_event_source *s, int fd, + uint32_t revents, void *userdata) { + sd_dhcp_client *client = userdata; + _cleanup_free_ DHCPMessage *message = NULL; + int buflen = 0, len, r; + const struct ether_addr zero_mac = { { 0, 0, 0, 0, 0, 0 } }; + const struct ether_addr *expected_chaddr = NULL; + uint8_t expected_hlen = 0; + + assert(s); + assert(client); + + r = ioctl(fd, FIONREAD, &buflen); + if (r < 0) + return -errno; + else if (buflen < 0) + /* this can't be right */ + return -EIO; + + message = malloc0(buflen); + if (!message) + return -ENOMEM; + + len = read(fd, message, buflen); + if (len < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + + log_dhcp_client(client, "Could not receive message from UDP socket: %m"); + return -errno; + } else if ((size_t)len < sizeof(DHCPMessage)) { + log_dhcp_client(client, "Too small to be a DHCP message: ignoring"); + return 0; + } + + if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) { + log_dhcp_client(client, "Not a DHCP message: ignoring"); + return 0; + } + + if (message->op != BOOTREPLY) { + log_dhcp_client(client, "Not a BOOTREPLY message: ignoring"); + return 0; + } + + if (message->htype != client->arp_type) { + log_dhcp_client(client, "Packet type does not match client type"); + return 0; + } + + if (client->arp_type == ARPHRD_ETHER) { + expected_hlen = ETH_ALEN; + expected_chaddr = (const struct ether_addr *) &client->mac_addr; + } else { + /* Non-Ethernet links expect zero chaddr */ + expected_hlen = 0; + expected_chaddr = &zero_mac; + } + + if (message->hlen != expected_hlen) { + log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen); + return 0; + } + + if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) { + log_dhcp_client(client, "Received chaddr does not match expected: ignoring"); + return 0; + } + + if (client->state != DHCP_STATE_BOUND && + be32toh(message->xid) != client->xid) { + /* in BOUND state, we may receive FORCERENEW with xid set by server, + so ignore the xid in this case */ + log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring", + be32toh(message->xid), client->xid); + return 0; + } + + return client_handle_message(client, message, len); +} + +static int client_receive_message_raw(sd_event_source *s, int fd, + uint32_t revents, void *userdata) { + sd_dhcp_client *client = userdata; + _cleanup_free_ DHCPPacket *packet = NULL; + uint8_t cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))]; + struct iovec iov = {}; + struct msghdr msg = { + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = cmsgbuf, + .msg_controllen = sizeof(cmsgbuf), + }; + struct cmsghdr *cmsg; + bool checksum = true; + int buflen = 0, len, r; + + assert(s); + assert(client); + + r = ioctl(fd, FIONREAD, &buflen); + if (r < 0) + return -errno; + else if (buflen < 0) + /* this can't be right */ + return -EIO; + + packet = malloc0(buflen); + if (!packet) + return -ENOMEM; + + iov.iov_base = packet; + iov.iov_len = buflen; + + len = recvmsg(fd, &msg, 0); + if (len < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + + log_dhcp_client(client, "Could not receive message from raw socket: %m"); + + return -errno; + } else if ((size_t)len < sizeof(DHCPPacket)) + return 0; + + CMSG_FOREACH(cmsg, &msg) { + if (cmsg->cmsg_level == SOL_PACKET && + cmsg->cmsg_type == PACKET_AUXDATA && + cmsg->cmsg_len == CMSG_LEN(sizeof(struct tpacket_auxdata))) { + struct tpacket_auxdata *aux = (struct tpacket_auxdata*)CMSG_DATA(cmsg); + + checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY); + break; + } + } + + r = dhcp_packet_verify_headers(packet, len, checksum); + if (r < 0) + return 0; + + len -= DHCP_IP_UDP_SIZE; + + return client_handle_message(client, &packet->dhcp, len); +} + +int sd_dhcp_client_start(sd_dhcp_client *client) { + int r; + + assert_return(client, -EINVAL); + + r = client_initialize(client); + if (r < 0) + return r; + + if (client->last_addr) + client->state = DHCP_STATE_INIT_REBOOT; + + r = client_start(client); + if (r >= 0) + log_dhcp_client(client, "STARTED on ifindex %i", client->index); + + return r; +} + +int sd_dhcp_client_stop(sd_dhcp_client *client) { + DHCP_CLIENT_DONT_DESTROY(client); + + assert_return(client, -EINVAL); + + client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); + client->state = DHCP_STATE_STOPPED; + + return 0; +} + +int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, + int priority) { + int r; + + assert_return(client, -EINVAL); + assert_return(!client->event, -EBUSY); + + if (event) + client->event = sd_event_ref(event); + else { + r = sd_event_default(&client->event); + if (r < 0) + return 0; + } + + client->event_priority = priority; + + return 0; +} + +int sd_dhcp_client_detach_event(sd_dhcp_client *client) { + assert_return(client, -EINVAL); + + client->event = sd_event_unref(client->event); + + return 0; +} + +sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) { + if (!client) + return NULL; + + return client->event; +} + +sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client) { + + if (!client) + return NULL; + + assert(client->n_ref >= 1); + client->n_ref++; + + return client; +} + +sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) { + + if (!client) + return NULL; + + assert(client->n_ref >= 1); + client->n_ref--; + + if (client->n_ref > 0) + return NULL; + + log_dhcp_client(client, "FREE"); + + client_initialize(client); + + client->receive_message = sd_event_source_unref(client->receive_message); + + sd_dhcp_client_detach_event(client); + + sd_dhcp_lease_unref(client->lease); + + free(client->req_opts); + free(client->hostname); + free(client->vendor_class_identifier); + free(client); + + return NULL; +} + +int sd_dhcp_client_new(sd_dhcp_client **ret) { + _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL; + + assert_return(ret, -EINVAL); + + client = new0(sd_dhcp_client, 1); + if (!client) + return -ENOMEM; + + client->n_ref = 1; + client->state = DHCP_STATE_INIT; + client->index = -1; + client->fd = -1; + client->attempt = 1; + client->mtu = DHCP_DEFAULT_MIN_SIZE; + + client->req_opts_size = ELEMENTSOF(default_req_opts); + + client->req_opts = memdup(default_req_opts, client->req_opts_size); + if (!client->req_opts) + return -ENOMEM; + + *ret = client; + client = NULL; + + return 0; +} diff --git a/src/systemd/src/libsystemd-network/sd-dhcp-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c new file mode 100644 index 00000000..e6caab54 --- /dev/null +++ b/src/systemd/src/libsystemd-network/sd-dhcp-lease.c @@ -0,0 +1,1145 @@ +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + Copyright (C) 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include + +#include "sd-dhcp-lease.h" + +#include "alloc-util.h" +#include "dhcp-lease-internal.h" +#include "dhcp-protocol.h" +#include "dns-domain.h" +#include "fd-util.h" +#include "fileio.h" +#include "hexdecoct.h" +#include "hostname-util.h" +#include "in-addr-util.h" +#include "network-internal.h" +#include "parse-util.h" +#include "string-util.h" +#include "unaligned.h" + +int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + if (lease->address == 0) + return -ENODATA; + + addr->s_addr = lease->address; + return 0; +} + +int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + if (!lease->have_broadcast) + return -ENODATA; + + addr->s_addr = lease->broadcast; + return 0; +} + +int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) { + assert_return(lease, -EINVAL); + assert_return(lifetime, -EINVAL); + + if (lease->lifetime <= 0) + return -ENODATA; + + *lifetime = lease->lifetime; + return 0; +} + +int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1) { + assert_return(lease, -EINVAL); + assert_return(t1, -EINVAL); + + if (lease->t1 <= 0) + return -ENODATA; + + *t1 = lease->t1; + return 0; +} + +int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2) { + assert_return(lease, -EINVAL); + assert_return(t2, -EINVAL); + + if (lease->t2 <= 0) + return -ENODATA; + + *t2 = lease->t2; + return 0; +} + +int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) { + assert_return(lease, -EINVAL); + assert_return(mtu, -EINVAL); + + if (lease->mtu <= 0) + return -ENODATA; + + *mtu = lease->mtu; + return 0; +} + +int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + if (lease->dns_size <= 0) + return -ENODATA; + + *addr = lease->dns; + return (int) lease->dns_size; +} + +int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + if (lease->ntp_size <= 0) + return -ENODATA; + + *addr = lease->ntp; + return (int) lease->ntp_size; +} + +int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) { + assert_return(lease, -EINVAL); + assert_return(domainname, -EINVAL); + + if (!lease->domainname) + return -ENODATA; + + *domainname = lease->domainname; + return 0; +} + +int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) { + assert_return(lease, -EINVAL); + assert_return(hostname, -EINVAL); + + if (!lease->hostname) + return -ENODATA; + + *hostname = lease->hostname; + return 0; +} + +int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) { + assert_return(lease, -EINVAL); + assert_return(root_path, -EINVAL); + + if (!lease->root_path) + return -ENODATA; + + *root_path = lease->root_path; + return 0; +} + +int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + if (lease->router == 0) + return -ENODATA; + + addr->s_addr = lease->router; + return 0; +} + +int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + if (!lease->have_subnet_mask) + return -ENODATA; + + addr->s_addr = lease->subnet_mask; + return 0; +} + +int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + if (lease->server_address == 0) + return -ENODATA; + + addr->s_addr = lease->server_address; + return 0; +} + +int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + + if (lease->next_server == 0) + return -ENODATA; + + addr->s_addr = lease->next_server; + return 0; +} + +int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes) { + assert_return(lease, -EINVAL); + assert_return(routes, -EINVAL); + + if (lease->static_route_size <= 0) + return -ENODATA; + + *routes = lease->static_route; + return (int) lease->static_route_size; +} + +int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) { + assert_return(lease, -EINVAL); + assert_return(data, -EINVAL); + assert_return(data_len, -EINVAL); + + if (lease->vendor_specific_len <= 0) + return -ENODATA; + + *data = lease->vendor_specific; + *data_len = lease->vendor_specific_len; + return 0; +} + +sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) { + + if (!lease) + return NULL; + + assert(lease->n_ref >= 1); + lease->n_ref++; + + return lease; +} + +sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease) { + + if (!lease) + return NULL; + + assert(lease->n_ref >= 1); + lease->n_ref--; + + if (lease->n_ref > 0) + return NULL; + + while (lease->private_options) { + struct sd_dhcp_raw_option *option = lease->private_options; + + LIST_REMOVE(options, lease->private_options, option); + + free(option->data); + free(option); + } + + free(lease->hostname); + free(lease->domainname); + free(lease->dns); + free(lease->ntp); + free(lease->static_route); + free(lease->client_id); + free(lease->vendor_specific); + free(lease); + + return NULL; +} + +static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) { + assert(option); + assert(ret); + + if (len != 4) + return -EINVAL; + + *ret = unaligned_read_be32((be32_t*) option); + if (*ret < min) + *ret = min; + + return 0; +} + +static int lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) { + assert(option); + assert(ret); + + if (len != 2) + return -EINVAL; + + *ret = unaligned_read_be16((be16_t*) option); + if (*ret < min) + *ret = min; + + return 0; +} + +static int lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) { + assert(option); + assert(ret); + + if (len != 4) + return -EINVAL; + + memcpy(ret, option, 4); + return 0; +} + +static int lease_parse_string(const uint8_t *option, size_t len, char **ret) { + assert(option); + assert(ret); + + if (len <= 0) + *ret = mfree(*ret); + else { + char *string; + + /* + * One trailing NUL byte is OK, we don't mind. See: + * https://github.com/systemd/systemd/issues/1337 + */ + if (memchr(option, 0, len - 1)) + return -EINVAL; + + string = strndup((const char *) option, len); + if (!string) + return -ENOMEM; + + free(*ret); + *ret = string; + } + + return 0; +} + +static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) { + assert(option); + assert(ret); + assert(n_ret); + + if (len <= 0) { + *ret = mfree(*ret); + *n_ret = 0; + } else { + size_t n_addresses; + struct in_addr *addresses; + + if (len % 4 != 0) + return -EINVAL; + + n_addresses = len / 4; + + addresses = newdup(struct in_addr, option, n_addresses); + if (!addresses) + return -ENOMEM; + + free(*ret); + *ret = addresses; + *n_ret = n_addresses; + } + + return 0; +} + +static int lease_parse_routes( + const uint8_t *option, size_t len, + struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) { + + struct in_addr addr; + + assert(option || len <= 0); + assert(routes); + assert(routes_size); + assert(routes_allocated); + + if (len <= 0) + return 0; + + if (len % 8 != 0) + return -EINVAL; + + if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + (len / 8))) + return -ENOMEM; + + while (len >= 8) { + struct sd_dhcp_route *route = *routes + *routes_size; + int r; + + r = in_addr_default_prefixlen((struct in_addr*) option, &route->dst_prefixlen); + if (r < 0) { + log_debug("Failed to determine destination prefix length from class based IP, ignoring"); + continue; + } + + assert_se(lease_parse_be32(option, 4, &addr.s_addr) >= 0); + route->dst_addr = inet_makeaddr(inet_netof(addr), 0); + option += 4; + + assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0); + option += 4; + + len -= 8; + (*routes_size)++; + } + + return 0; +} + +/* parses RFC3442 Classless Static Route Option */ +static int lease_parse_classless_routes( + const uint8_t *option, size_t len, + struct sd_dhcp_route **routes, size_t *routes_size, size_t *routes_allocated) { + + assert(option || len <= 0); + assert(routes); + assert(routes_size); + assert(routes_allocated); + + if (len <= 0) + return 0; + + /* option format: (subnet-mask-width significant-subnet-octets gateway-ip)* */ + + while (len > 0) { + uint8_t dst_octets; + struct sd_dhcp_route *route; + + if (!GREEDY_REALLOC(*routes, *routes_allocated, *routes_size + 1)) + return -ENOMEM; + + route = *routes + *routes_size; + + dst_octets = (*option == 0 ? 0 : ((*option - 1) / 8) + 1); + route->dst_prefixlen = *option; + option++; + len--; + + /* can't have more than 4 octets in IPv4 */ + if (dst_octets > 4 || len < dst_octets) + return -EINVAL; + + route->dst_addr.s_addr = 0; + memcpy(&route->dst_addr.s_addr, option, dst_octets); + option += dst_octets; + len -= dst_octets; + + if (len < 4) + return -EINVAL; + + lease_parse_be32(option, 4, &route->gw_addr.s_addr); + option += 4; + len -= 4; + + (*routes_size)++; + } + + return 0; +} + +int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) { + sd_dhcp_lease *lease = userdata; + int r; + + assert(lease); + + switch(code) { + + case DHCP_OPTION_IP_ADDRESS_LEASE_TIME: + r = lease_parse_u32(option, len, &lease->lifetime, 1); + if (r < 0) + log_debug_errno(r, "Failed to parse lease time, ignoring: %m"); + + break; + + case DHCP_OPTION_SERVER_IDENTIFIER: + r = lease_parse_be32(option, len, &lease->server_address); + if (r < 0) + log_debug_errno(r, "Failed to parse server identifier, ignoring: %m"); + + break; + + case DHCP_OPTION_SUBNET_MASK: + r = lease_parse_be32(option, len, &lease->subnet_mask); + if (r < 0) + log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m"); + else + lease->have_subnet_mask = true; + break; + + case DHCP_OPTION_BROADCAST: + r = lease_parse_be32(option, len, &lease->broadcast); + if (r < 0) + log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m"); + else + lease->have_broadcast = true; + break; + + case DHCP_OPTION_ROUTER: + if (len >= 4) { + r = lease_parse_be32(option, 4, &lease->router); + if (r < 0) + log_debug_errno(r, "Failed to parse router address, ignoring: %m"); + } + break; + + case DHCP_OPTION_DOMAIN_NAME_SERVER: + r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size); + if (r < 0) + log_debug_errno(r, "Failed to parse DNS server, ignoring: %m"); + break; + + case DHCP_OPTION_NTP_SERVER: + r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size); + if (r < 0) + log_debug_errno(r, "Failed to parse NTP server, ignoring: %m"); + break; + + case DHCP_OPTION_STATIC_ROUTE: + r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, &lease->static_route_allocated); + if (r < 0) + log_debug_errno(r, "Failed to parse static routes, ignoring: %m"); + break; + + case DHCP_OPTION_INTERFACE_MTU: + r = lease_parse_u16(option, len, &lease->mtu, 68); + if (r < 0) + log_debug_errno(r, "Failed to parse MTU, ignoring: %m"); + break; + + case DHCP_OPTION_DOMAIN_NAME: { + _cleanup_free_ char *domainname = NULL, *normalized = NULL; + + r = lease_parse_string(option, len, &domainname); + if (r < 0) { + log_debug_errno(r, "Failed to parse domain name, ignoring: %m"); + return 0; + } + + r = dns_name_normalize(domainname, &normalized); + if (r < 0) { + log_debug_errno(r, "Failed to normalize domain name '%s': %m", domainname); + return 0; + } + + if (is_localhost(normalized)) { + log_debug_errno(r, "Detected 'localhost' as suggested domain name, ignoring."); + break; + } + + free(lease->domainname); + lease->domainname = normalized; + normalized = NULL; + + break; + } + + case DHCP_OPTION_HOST_NAME: { + _cleanup_free_ char *hostname = NULL, *normalized = NULL; + + r = lease_parse_string(option, len, &hostname); + if (r < 0) { + log_debug_errno(r, "Failed to parse host name, ignoring: %m"); + return 0; + } + + r = dns_name_normalize(hostname, &normalized); + if (r < 0) { + log_debug_errno(r, "Failed to normalize host name '%s', ignoring: %m", hostname); + return 0; + } + + if (is_localhost(normalized)) { + log_debug_errno(r, "Detected 'localhost' as suggested host name, ignoring."); + return 0; + } + + free(lease->hostname); + lease->hostname = normalized; + normalized = NULL; + + break; + } + + case DHCP_OPTION_ROOT_PATH: + r = lease_parse_string(option, len, &lease->root_path); + if (r < 0) + log_debug_errno(r, "Failed to parse root path, ignoring: %m"); + break; + + case DHCP_OPTION_RENEWAL_T1_TIME: + r = lease_parse_u32(option, len, &lease->t1, 1); + if (r < 0) + log_debug_errno(r, "Failed to parse T1 time, ignoring: %m"); + break; + + case DHCP_OPTION_REBINDING_T2_TIME: + r = lease_parse_u32(option, len, &lease->t2, 1); + if (r < 0) + log_debug_errno(r, "Failed to parse T2 time, ignoring: %m"); + break; + + case DHCP_OPTION_CLASSLESS_STATIC_ROUTE: + r = lease_parse_classless_routes( + option, len, + &lease->static_route, + &lease->static_route_size, + &lease->static_route_allocated); + if (r < 0) + log_debug_errno(r, "Failed to parse classless routes, ignoring: %m"); + break; + + case DHCP_OPTION_NEW_TZDB_TIMEZONE: { + _cleanup_free_ char *tz = NULL; + + r = lease_parse_string(option, len, &tz); + if (r < 0) { + log_debug_errno(r, "Failed to parse timezone option, ignoring: %m"); + return 0; + } + + if (!timezone_is_valid(tz)) { + log_debug_errno(r, "Timezone is not valid, ignoring: %m"); + return 0; + } + + free(lease->timezone); + lease->timezone = tz; + tz = NULL; + + break; + } + + case DHCP_OPTION_VENDOR_SPECIFIC: + + if (len <= 0) + lease->vendor_specific = mfree(lease->vendor_specific); + else { + void *p; + + p = memdup(option, len); + if (!p) + return -ENOMEM; + + free(lease->vendor_specific); + lease->vendor_specific = p; + } + + lease->vendor_specific_len = len; + break; + + case DHCP_OPTION_PRIVATE_BASE ... DHCP_OPTION_PRIVATE_LAST: + r = dhcp_lease_insert_private_option(lease, code, option, len); + if (r < 0) + return r; + + break; + + default: + log_debug("Ignoring option DHCP option %"PRIu8" while parsing.", code); + break; + } + + return 0; +} + +int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len) { + struct sd_dhcp_raw_option *cur, *option; + + assert(lease); + + LIST_FOREACH(options, cur, lease->private_options) { + if (tag < cur->tag) + break; + if (tag == cur->tag) { + log_debug("Ignoring duplicate option, tagged %i.", tag); + return 0; + } + } + + option = new(struct sd_dhcp_raw_option, 1); + if (!option) + return -ENOMEM; + + option->tag = tag; + option->length = len; + option->data = memdup(data, len); + if (!option->data) { + free(option); + return -ENOMEM; + } + + LIST_INSERT_BEFORE(options, lease->private_options, cur, option); + return 0; +} + +int dhcp_lease_new(sd_dhcp_lease **ret) { + sd_dhcp_lease *lease; + + lease = new0(sd_dhcp_lease, 1); + if (!lease) + return -ENOMEM; + + lease->router = INADDR_ANY; + lease->n_ref = 1; + + *ret = lease; + return 0; +} + +int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + struct sd_dhcp_raw_option *option; + struct in_addr address; + const struct in_addr *addresses; + const void *client_id, *data; + size_t client_id_len, data_len; + const char *string; + uint16_t mtu; + struct sd_dhcp_route *routes; + uint32_t t1, t2, lifetime; + int r; + + assert(lease); + assert(lease_file); + + r = fopen_temporary(lease_file, &f, &temp_path); + if (r < 0) + goto fail; + + fchmod(fileno(f), 0644); + + fprintf(f, + "# This is private data. Do not parse.\n"); + + r = sd_dhcp_lease_get_address(lease, &address); + if (r >= 0) + fprintf(f, "ADDRESS=%s\n", inet_ntoa(address)); + + r = sd_dhcp_lease_get_netmask(lease, &address); + if (r >= 0) + fprintf(f, "NETMASK=%s\n", inet_ntoa(address)); + + r = sd_dhcp_lease_get_router(lease, &address); + if (r >= 0) + fprintf(f, "ROUTER=%s\n", inet_ntoa(address)); + + r = sd_dhcp_lease_get_server_identifier(lease, &address); + if (r >= 0) + fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntoa(address)); + + r = sd_dhcp_lease_get_next_server(lease, &address); + if (r >= 0) + fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address)); + + r = sd_dhcp_lease_get_broadcast(lease, &address); + if (r >= 0) + fprintf(f, "BROADCAST=%s\n", inet_ntoa(address)); + + r = sd_dhcp_lease_get_mtu(lease, &mtu); + if (r >= 0) + fprintf(f, "MTU=%" PRIu16 "\n", mtu); + + r = sd_dhcp_lease_get_t1(lease, &t1); + if (r >= 0) + fprintf(f, "T1=%" PRIu32 "\n", t1); + + r = sd_dhcp_lease_get_t2(lease, &t2); + if (r >= 0) + fprintf(f, "T2=%" PRIu32 "\n", t2); + + r = sd_dhcp_lease_get_lifetime(lease, &lifetime); + if (r >= 0) + fprintf(f, "LIFETIME=%" PRIu32 "\n", lifetime); + + r = sd_dhcp_lease_get_dns(lease, &addresses); + if (r > 0) { + fputs("DNS=", f); + serialize_in_addrs(f, addresses, r); + fputs("\n", f); + } + + r = sd_dhcp_lease_get_ntp(lease, &addresses); + if (r > 0) { + fputs("NTP=", f); + serialize_in_addrs(f, addresses, r); + fputs("\n", f); + } + + r = sd_dhcp_lease_get_domainname(lease, &string); + if (r >= 0) + fprintf(f, "DOMAINNAME=%s\n", string); + + r = sd_dhcp_lease_get_hostname(lease, &string); + if (r >= 0) + fprintf(f, "HOSTNAME=%s\n", string); + + r = sd_dhcp_lease_get_root_path(lease, &string); + if (r >= 0) + fprintf(f, "ROOT_PATH=%s\n", string); + + r = sd_dhcp_lease_get_routes(lease, &routes); + if (r > 0) + serialize_dhcp_routes(f, "ROUTES", routes, r); + + r = sd_dhcp_lease_get_timezone(lease, &string); + if (r >= 0) + fprintf(f, "TIMEZONE=%s\n", string); + + r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len); + if (r >= 0) { + _cleanup_free_ char *client_id_hex = NULL; + + client_id_hex = hexmem(client_id, client_id_len); + if (!client_id_hex) { + r = -ENOMEM; + goto fail; + } + fprintf(f, "CLIENTID=%s\n", client_id_hex); + } + + r = sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len); + if (r >= 0) { + _cleanup_free_ char *option_hex = NULL; + + option_hex = hexmem(data, data_len); + if (!option_hex) { + r = -ENOMEM; + goto fail; + } + fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex); + } + + LIST_FOREACH(options, option, lease->private_options) { + char key[strlen("OPTION_000")+1]; + + snprintf(key, sizeof(key), "OPTION_%"PRIu8, option->tag); + r = serialize_dhcp_option(f, key, option->data, option->length); + if (r < 0) + goto fail; + } + + r = fflush_and_check(f); + if (r < 0) + goto fail; + + if (rename(temp_path, lease_file) < 0) { + r = -errno; + goto fail; + } + + return 0; + +fail: + if (temp_path) + (void) unlink(temp_path); + + return log_error_errno(r, "Failed to save lease data %s: %m", lease_file); +} + +int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { + + _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; + _cleanup_free_ char + *address = NULL, + *router = NULL, + *netmask = NULL, + *server_address = NULL, + *next_server = NULL, + *broadcast = NULL, + *dns = NULL, + *ntp = NULL, + *mtu = NULL, + *routes = NULL, + *client_id_hex = NULL, + *vendor_specific_hex = NULL, + *lifetime = NULL, + *t1 = NULL, + *t2 = NULL, + *options[DHCP_OPTION_PRIVATE_LAST - DHCP_OPTION_PRIVATE_BASE + 1] = {}; + + int r, i; + + assert(lease_file); + assert(ret); + + r = dhcp_lease_new(&lease); + if (r < 0) + return r; + + r = parse_env_file(lease_file, NEWLINE, + "ADDRESS", &address, + "ROUTER", &router, + "NETMASK", &netmask, + "SERVER_IDENTIFIER", &server_address, + "NEXT_SERVER", &next_server, + "BROADCAST", &broadcast, + "DNS", &dns, + "NTP", &ntp, + "MTU", &mtu, + "DOMAINNAME", &lease->domainname, + "HOSTNAME", &lease->hostname, + "ROOT_PATH", &lease->root_path, + "ROUTES", &routes, + "CLIENTID", &client_id_hex, + "TIMEZONE", &lease->timezone, + "VENDOR_SPECIFIC", &vendor_specific_hex, + "LIFETIME", &lifetime, + "T1", &t1, + "T2", &t2, + "OPTION_224", &options[0], + "OPTION_225", &options[1], + "OPTION_226", &options[2], + "OPTION_227", &options[3], + "OPTION_228", &options[4], + "OPTION_229", &options[5], + "OPTION_230", &options[6], + "OPTION_231", &options[7], + "OPTION_232", &options[8], + "OPTION_233", &options[9], + "OPTION_234", &options[10], + "OPTION_235", &options[11], + "OPTION_236", &options[12], + "OPTION_237", &options[13], + "OPTION_238", &options[14], + "OPTION_239", &options[15], + "OPTION_240", &options[16], + "OPTION_241", &options[17], + "OPTION_242", &options[18], + "OPTION_243", &options[19], + "OPTION_244", &options[20], + "OPTION_245", &options[21], + "OPTION_246", &options[22], + "OPTION_247", &options[23], + "OPTION_248", &options[24], + "OPTION_249", &options[25], + "OPTION_250", &options[26], + "OPTION_251", &options[27], + "OPTION_252", &options[28], + "OPTION_253", &options[29], + "OPTION_254", &options[30], + NULL); + if (r < 0) + return r; + + if (address) { + r = inet_pton(AF_INET, address, &lease->address); + if (r <= 0) + log_debug("Failed to parse address %s, ignoring.", address); + } + + if (router) { + r = inet_pton(AF_INET, router, &lease->router); + if (r <= 0) + log_debug("Failed to parse router %s, ignoring.", router); + } + + if (netmask) { + r = inet_pton(AF_INET, netmask, &lease->subnet_mask); + if (r <= 0) + log_debug("Failed to parse netmask %s, ignoring.", netmask); + else + lease->have_subnet_mask = true; + } + + if (server_address) { + r = inet_pton(AF_INET, server_address, &lease->server_address); + if (r <= 0) + log_debug("Failed to parse server address %s, ignoring.", server_address); + } + + if (next_server) { + r = inet_pton(AF_INET, next_server, &lease->next_server); + if (r <= 0) + log_debug("Failed to parse next server %s, ignoring.", next_server); + } + + if (broadcast) { + r = inet_pton(AF_INET, broadcast, &lease->broadcast); + if (r <= 0) + log_debug("Failed to parse broadcast address %s, ignoring.", broadcast); + else + lease->have_broadcast = true; + } + + if (dns) { + r = deserialize_in_addrs(&lease->dns, dns); + if (r < 0) + log_debug_errno(r, "Failed to deserialize DNS servers %s, ignoring: %m", dns); + else + lease->dns_size = r; + } + + if (ntp) { + r = deserialize_in_addrs(&lease->ntp, ntp); + if (r < 0) + log_debug_errno(r, "Failed to deserialize NTP servers %s, ignoring: %m", ntp); + else + lease->ntp_size = r; + } + + if (mtu) { + r = safe_atou16(mtu, &lease->mtu); + if (r < 0) + log_debug_errno(r, "Failed to parse MTU %s, ignoring: %m", mtu); + } + + if (routes) { + r = deserialize_dhcp_routes( + &lease->static_route, + &lease->static_route_size, + &lease->static_route_allocated, + routes); + if (r < 0) + log_debug_errno(r, "Failed to parse DHCP routes %s, ignoring: %m", routes); + } + + if (lifetime) { + r = safe_atou32(lifetime, &lease->lifetime); + if (r < 0) + log_debug_errno(r, "Failed to parse lifetime %s, ignoring: %m", lifetime); + } + + if (t1) { + r = safe_atou32(t1, &lease->t1); + if (r < 0) + log_debug_errno(r, "Failed to parse T1 %s, ignoring: %m", t1); + } + + if (t2) { + r = safe_atou32(t2, &lease->t2); + if (r < 0) + log_debug_errno(r, "Failed to parse T2 %s, ignoring: %m", t2); + } + + if (client_id_hex) { + r = deserialize_dhcp_option(&lease->client_id, &lease->client_id_len, client_id_hex); + if (r < 0) + log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex); + } + + if (vendor_specific_hex) { + r = deserialize_dhcp_option(&lease->vendor_specific, &lease->vendor_specific_len, vendor_specific_hex); + if (r < 0) + log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex); + } + + for (i = 0; i <= DHCP_OPTION_PRIVATE_LAST - DHCP_OPTION_PRIVATE_BASE; i++) { + _cleanup_free_ void *data = NULL; + size_t len; + + if (!options[i]) + continue; + + r = deserialize_dhcp_option(&data, &len, options[i]); + if (r < 0) { + log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]); + continue; + } + + r = dhcp_lease_insert_private_option(lease, DHCP_OPTION_PRIVATE_BASE + i, data, len); + if (r < 0) + return r; + } + + *ret = lease; + lease = NULL; + + return 0; +} + +int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) { + struct in_addr address, mask; + int r; + + assert(lease); + + if (lease->address == 0) + return -ENODATA; + + address.s_addr = lease->address; + + /* fall back to the default subnet masks based on address class */ + r = in_addr_default_subnet_mask(&address, &mask); + if (r < 0) + return r; + + lease->subnet_mask = mask.s_addr; + lease->have_subnet_mask = true; + + return 0; +} + +int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) { + assert_return(lease, -EINVAL); + assert_return(client_id, -EINVAL); + assert_return(client_id_len, -EINVAL); + + if (!lease->client_id) + return -ENODATA; + + *client_id = lease->client_id; + *client_id_len = lease->client_id_len; + + return 0; +} + +int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len) { + assert_return(lease, -EINVAL); + assert_return(client_id || client_id_len <= 0, -EINVAL); + + if (client_id_len <= 0) + lease->client_id = mfree(lease->client_id); + else { + void *p; + + p = memdup(client_id, client_id_len); + if (!p) + return -ENOMEM; + + free(lease->client_id); + lease->client_id = p; + lease->client_id_len = client_id_len; + } + + return 0; +} + +int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) { + assert_return(lease, -EINVAL); + assert_return(tz, -EINVAL); + + if (!lease->timezone) + return -ENODATA; + + *tz = lease->timezone; + return 0; +} diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-client.c b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c new file mode 100644 index 00000000..64793fc6 --- /dev/null +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-client.c @@ -0,0 +1,1309 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "sd-dhcp6-client.h" + +#include "alloc-util.h" +#include "dhcp-identifier.h" +#include "dhcp6-internal.h" +#include "dhcp6-lease-internal.h" +#include "dhcp6-protocol.h" +#include "fd-util.h" +#include "in-addr-util.h" +#include "network-internal.h" +#include "random-util.h" +#include "string-table.h" +#include "util.h" + +#define MAX_MAC_ADDR_LEN INFINIBAND_ALEN + +struct sd_dhcp6_client { + unsigned n_ref; + + enum DHCP6State state; + sd_event *event; + int event_priority; + int index; + struct in6_addr local_address; + uint8_t mac_addr[MAX_MAC_ADDR_LEN]; + size_t mac_addr_len; + uint16_t arp_type; + DHCP6IA ia_na; + be32_t transaction_id; + usec_t transaction_start; + struct sd_dhcp6_lease *lease; + int fd; + bool information_request; + be16_t *req_opts; + size_t req_opts_allocated; + size_t req_opts_len; + sd_event_source *receive_message; + usec_t retransmit_time; + uint8_t retransmit_count; + sd_event_source *timeout_resend; + sd_event_source *timeout_resend_expire; + sd_dhcp6_client_cb_t cb; + void *userdata; + struct duid duid; + size_t duid_len; +}; + +static const uint16_t default_req_opts[] = { + DHCP6_OPTION_DNS_SERVERS, + DHCP6_OPTION_DOMAIN_LIST, + DHCP6_OPTION_NTP_SERVER, + DHCP6_OPTION_SNTP_SERVERS, +}; + +const char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = { + [DHCP6_SOLICIT] = "SOLICIT", + [DHCP6_ADVERTISE] = "ADVERTISE", + [DHCP6_REQUEST] = "REQUEST", + [DHCP6_CONFIRM] = "CONFIRM", + [DHCP6_RENEW] = "RENEW", + [DHCP6_REBIND] = "REBIND", + [DHCP6_REPLY] = "REPLY", + [DHCP6_RELEASE] = "RELEASE", + [DHCP6_DECLINE] = "DECLINE", + [DHCP6_RECONFIGURE] = "RECONFIGURE", + [DHCP6_INFORMATION_REQUEST] = "INFORMATION-REQUEST", + [DHCP6_RELAY_FORW] = "RELAY-FORW", + [DHCP6_RELAY_REPL] = "RELAY-REPL", +}; + +DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_type, int); + +const char * dhcp6_message_status_table[_DHCP6_STATUS_MAX] = { + [DHCP6_STATUS_SUCCESS] = "Success", + [DHCP6_STATUS_UNSPEC_FAIL] = "Unspecified failure", + [DHCP6_STATUS_NO_ADDRS_AVAIL] = "No addresses available", + [DHCP6_STATUS_NO_BINDING] = "Binding unavailable", + [DHCP6_STATUS_NOT_ON_LINK] = "Not on link", + [DHCP6_STATUS_USE_MULTICAST] = "Use multicast", +}; + +DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int); + +#define DHCP6_CLIENT_DONT_DESTROY(client) \ + _cleanup_(sd_dhcp6_client_unrefp) _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client) + +static int client_start(sd_dhcp6_client *client, enum DHCP6State state); + +int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, sd_dhcp6_client_cb_t cb, void *userdata) { + assert_return(client, -EINVAL); + + client->cb = cb; + client->userdata = userdata; + + return 0; +} + +int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index) { + assert_return(client, -EINVAL); + assert_return(interface_index >= -1, -EINVAL); + + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + + client->index = interface_index; + + return 0; +} + +int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address) { + assert_return(client, -EINVAL); + assert_return(local_address, -EINVAL); + assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0, -EINVAL); + + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + + client->local_address = *local_address; + + return 0; +} + +int sd_dhcp6_client_set_mac( + sd_dhcp6_client *client, + const uint8_t *addr, size_t addr_len, + uint16_t arp_type) { + + assert_return(client, -EINVAL); + assert_return(addr, -EINVAL); + assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL); + assert_return(arp_type > 0, -EINVAL); + + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + + if (arp_type == ARPHRD_ETHER) + assert_return(addr_len == ETH_ALEN, -EINVAL); + else if (arp_type == ARPHRD_INFINIBAND) + assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); + else + return -EINVAL; + + if (client->mac_addr_len == addr_len && + memcmp(&client->mac_addr, addr, addr_len) == 0) + return 0; + + memcpy(&client->mac_addr, addr, addr_len); + client->mac_addr_len = addr_len; + client->arp_type = arp_type; + + return 0; +} + +static int client_ensure_duid(sd_dhcp6_client *client) { + if (client->duid_len != 0) + return 0; + + return dhcp_identifier_set_duid_en(&client->duid, &client->duid_len); +} + +int sd_dhcp6_client_set_duid( + sd_dhcp6_client *client, + uint16_t type, + uint8_t *duid, size_t duid_len) { + assert_return(client, -EINVAL); + assert_return(duid, -EINVAL); + assert_return(duid_len > 0 && duid_len <= MAX_DUID_LEN, -EINVAL); + + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + + switch (type) { + case DHCP6_DUID_LLT: + if (duid_len <= sizeof(client->duid.llt)) + return -EINVAL; + break; + case DHCP6_DUID_EN: + if (duid_len != sizeof(client->duid.en)) + return -EINVAL; + break; + case DHCP6_DUID_LL: + if (duid_len <= sizeof(client->duid.ll)) + return -EINVAL; + break; + case DHCP6_DUID_UUID: + if (duid_len != sizeof(client->duid.uuid)) + return -EINVAL; + break; + default: + /* accept unknown type in order to be forward compatible */ + break; + } + + client->duid.type = htobe16(type); + memcpy(&client->duid.raw.data, duid, duid_len); + client->duid_len = duid_len + sizeof(client->duid.type); + + return 0; +} + +int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled) { + assert_return(client, -EINVAL); + assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); + + client->information_request = enabled; + + return 0; +} + +int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled) { + assert_return(client, -EINVAL); + assert_return(enabled, -EINVAL); + + *enabled = client->information_request; + + return 0; +} + +int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) { + size_t t; + + assert_return(client, -EINVAL); + assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY); + + switch(option) { + case DHCP6_OPTION_DNS_SERVERS: + case DHCP6_OPTION_DOMAIN_LIST: + case DHCP6_OPTION_SNTP_SERVERS: + case DHCP6_OPTION_NTP_SERVER: + break; + + default: + return -EINVAL; + } + + for (t = 0; t < client->req_opts_len; t++) + if (client->req_opts[t] == htobe16(option)) + return -EEXIST; + + if (!GREEDY_REALLOC(client->req_opts, client->req_opts_allocated, + client->req_opts_len + 1)) + return -ENOMEM; + + client->req_opts[client->req_opts_len++] = htobe16(option); + + return 0; +} + +int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret) { + assert_return(client, -EINVAL); + + if (!client->lease) + return -ENOMSG; + + if (ret) + *ret = client->lease; + + return 0; +} + +static void client_notify(sd_dhcp6_client *client, int event) { + if (client->cb) + client->cb(client, event, client->userdata); +} + +static void client_set_lease(sd_dhcp6_client *client, sd_dhcp6_lease *lease) { + if (client->lease) { + dhcp6_lease_clear_timers(&client->lease->ia); + sd_dhcp6_lease_unref(client->lease); + } + client->lease = lease; +} + +static int client_reset(sd_dhcp6_client *client) { + assert_return(client, -EINVAL); + + client_set_lease(client, NULL); + + client->receive_message = + sd_event_source_unref(client->receive_message); + + client->fd = safe_close(client->fd); + + client->transaction_id = 0; + client->transaction_start = 0; + + client->ia_na.timeout_t1 = + sd_event_source_unref(client->ia_na.timeout_t1); + client->ia_na.timeout_t2 = + sd_event_source_unref(client->ia_na.timeout_t2); + + client->retransmit_time = 0; + client->retransmit_count = 0; + client->timeout_resend = sd_event_source_unref(client->timeout_resend); + client->timeout_resend_expire = + sd_event_source_unref(client->timeout_resend_expire); + + client->state = DHCP6_STATE_STOPPED; + + return 0; +} + +static void client_stop(sd_dhcp6_client *client, int error) { + DHCP6_CLIENT_DONT_DESTROY(client); + + assert(client); + + client_notify(client, error); + + client_reset(client); +} + +static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { + _cleanup_free_ DHCP6Message *message = NULL; + struct in6_addr all_servers = + IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT; + size_t len, optlen = 512; + uint8_t *opt; + int r; + usec_t elapsed_usec; + be16_t elapsed_time; + + len = sizeof(DHCP6Message) + optlen; + + message = malloc0(len); + if (!message) + return -ENOMEM; + + opt = (uint8_t *)(message + 1); + + message->transaction_id = client->transaction_id; + + switch(client->state) { + case DHCP6_STATE_INFORMATION_REQUEST: + message->type = DHCP6_INFORMATION_REQUEST; + + break; + + case DHCP6_STATE_SOLICITATION: + message->type = DHCP6_SOLICIT; + + r = dhcp6_option_append(&opt, &optlen, + DHCP6_OPTION_RAPID_COMMIT, 0, NULL); + if (r < 0) + return r; + + r = dhcp6_option_append_ia(&opt, &optlen, &client->ia_na); + if (r < 0) + return r; + + break; + + case DHCP6_STATE_REQUEST: + case DHCP6_STATE_RENEW: + + if (client->state == DHCP6_STATE_REQUEST) + message->type = DHCP6_REQUEST; + else + message->type = DHCP6_RENEW; + + r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_SERVERID, + client->lease->serverid_len, + client->lease->serverid); + if (r < 0) + return r; + + r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia); + if (r < 0) + return r; + + break; + + case DHCP6_STATE_REBIND: + message->type = DHCP6_REBIND; + + r = dhcp6_option_append_ia(&opt, &optlen, &client->lease->ia); + if (r < 0) + return r; + + break; + + case DHCP6_STATE_STOPPED: + case DHCP6_STATE_BOUND: + return -EINVAL; + } + + r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ORO, + client->req_opts_len * sizeof(be16_t), + client->req_opts); + if (r < 0) + return r; + + assert (client->duid_len); + r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID, + client->duid_len, &client->duid); + if (r < 0) + return r; + + elapsed_usec = time_now - client->transaction_start; + if (elapsed_usec < 0xffff * USEC_PER_MSEC * 10) + elapsed_time = htobe16(elapsed_usec / USEC_PER_MSEC / 10); + else + elapsed_time = 0xffff; + + r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ELAPSED_TIME, + sizeof(elapsed_time), &elapsed_time); + if (r < 0) + return r; + + r = dhcp6_network_send_udp_socket(client->fd, &all_servers, message, + len - optlen); + if (r < 0) + return r; + + log_dhcp6_client(client, "Sent %s", + dhcp6_message_type_to_string(message->type)); + + return 0; +} + +static int client_timeout_t2(sd_event_source *s, uint64_t usec, + void *userdata) { + sd_dhcp6_client *client = userdata; + + assert_return(s, -EINVAL); + assert_return(client, -EINVAL); + assert_return(client->lease, -EINVAL); + + client->lease->ia.timeout_t2 = + sd_event_source_unref(client->lease->ia.timeout_t2); + + log_dhcp6_client(client, "Timeout T2"); + + client_start(client, DHCP6_STATE_REBIND); + + return 0; +} + +static int client_timeout_t1(sd_event_source *s, uint64_t usec, + void *userdata) { + sd_dhcp6_client *client = userdata; + + assert_return(s, -EINVAL); + assert_return(client, -EINVAL); + assert_return(client->lease, -EINVAL); + + client->lease->ia.timeout_t1 = + sd_event_source_unref(client->lease->ia.timeout_t1); + + log_dhcp6_client(client, "Timeout T1"); + + client_start(client, DHCP6_STATE_RENEW); + + return 0; +} + +static int client_timeout_resend_expire(sd_event_source *s, uint64_t usec, + void *userdata) { + sd_dhcp6_client *client = userdata; + DHCP6_CLIENT_DONT_DESTROY(client); + enum DHCP6State state; + + assert(s); + assert(client); + assert(client->event); + + state = client->state; + + client_stop(client, SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE); + + /* RFC 3315, section 18.1.4., says that "...the client may choose to + use a Solicit message to locate a new DHCP server..." */ + if (state == DHCP6_STATE_REBIND) + client_start(client, DHCP6_STATE_SOLICITATION); + + return 0; +} + +static usec_t client_timeout_compute_random(usec_t val) { + return val - val / 10 + + (random_u32() % (2 * USEC_PER_SEC)) * val / 10 / USEC_PER_SEC; +} + +static int client_timeout_resend(sd_event_source *s, uint64_t usec, + void *userdata) { + int r = 0; + sd_dhcp6_client *client = userdata; + usec_t time_now, init_retransmit_time = 0, max_retransmit_time = 0; + usec_t max_retransmit_duration = 0; + uint8_t max_retransmit_count = 0; + char time_string[FORMAT_TIMESPAN_MAX]; + uint32_t expire = 0; + + assert(s); + assert(client); + assert(client->event); + + client->timeout_resend = sd_event_source_unref(client->timeout_resend); + + switch (client->state) { + case DHCP6_STATE_INFORMATION_REQUEST: + init_retransmit_time = DHCP6_INF_TIMEOUT; + max_retransmit_time = DHCP6_INF_MAX_RT; + + break; + + case DHCP6_STATE_SOLICITATION: + + if (client->retransmit_count && client->lease) { + client_start(client, DHCP6_STATE_REQUEST); + return 0; + } + + init_retransmit_time = DHCP6_SOL_TIMEOUT; + max_retransmit_time = DHCP6_SOL_MAX_RT; + + break; + + case DHCP6_STATE_REQUEST: + init_retransmit_time = DHCP6_REQ_TIMEOUT; + max_retransmit_time = DHCP6_REQ_MAX_RT; + max_retransmit_count = DHCP6_REQ_MAX_RC; + + break; + + case DHCP6_STATE_RENEW: + init_retransmit_time = DHCP6_REN_TIMEOUT; + max_retransmit_time = DHCP6_REN_MAX_RT; + + /* RFC 3315, section 18.1.3. says max retransmit duration will + be the remaining time until T2. Instead of setting MRD, + wait for T2 to trigger with the same end result */ + + break; + + case DHCP6_STATE_REBIND: + init_retransmit_time = DHCP6_REB_TIMEOUT; + max_retransmit_time = DHCP6_REB_MAX_RT; + + if (!client->timeout_resend_expire) { + r = dhcp6_lease_ia_rebind_expire(&client->lease->ia, + &expire); + if (r < 0) { + client_stop(client, r); + return 0; + } + max_retransmit_duration = expire * USEC_PER_SEC; + } + + break; + + case DHCP6_STATE_STOPPED: + case DHCP6_STATE_BOUND: + return 0; + } + + if (max_retransmit_count && + client->retransmit_count >= max_retransmit_count) { + client_stop(client, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX); + return 0; + } + + r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); + if (r < 0) + goto error; + + r = client_send_message(client, time_now); + if (r >= 0) + client->retransmit_count++; + + if (!client->retransmit_time) { + client->retransmit_time = + client_timeout_compute_random(init_retransmit_time); + + if (client->state == DHCP6_STATE_SOLICITATION) + client->retransmit_time += init_retransmit_time / 10; + + } else { + if (max_retransmit_time && + client->retransmit_time > max_retransmit_time / 2) + client->retransmit_time = client_timeout_compute_random(max_retransmit_time); + else + client->retransmit_time += client_timeout_compute_random(client->retransmit_time); + } + + log_dhcp6_client(client, "Next retransmission in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->retransmit_time, USEC_PER_SEC)); + + r = sd_event_add_time(client->event, &client->timeout_resend, + clock_boottime_or_monotonic(), + time_now + client->retransmit_time, + 10 * USEC_PER_MSEC, client_timeout_resend, + client); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(client->timeout_resend, + client->event_priority); + if (r < 0) + goto error; + + r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timer"); + if (r < 0) + goto error; + + if (max_retransmit_duration && !client->timeout_resend_expire) { + + log_dhcp6_client(client, "Max retransmission duration %"PRIu64" secs", + max_retransmit_duration / USEC_PER_SEC); + + r = sd_event_add_time(client->event, + &client->timeout_resend_expire, + clock_boottime_or_monotonic(), + time_now + max_retransmit_duration, + USEC_PER_SEC, + client_timeout_resend_expire, client); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(client->timeout_resend_expire, + client->event_priority); + if (r < 0) + goto error; + + r = sd_event_source_set_description(client->timeout_resend_expire, "dhcp6-resend-expire-timer"); + if (r < 0) + goto error; + } + +error: + if (r < 0) + client_stop(client, r); + + return 0; +} + +static int client_ensure_iaid(sd_dhcp6_client *client) { + int r; + + assert(client); + + if (client->ia_na.id) + return 0; + + r = dhcp_identifier_set_iaid(client->index, client->mac_addr, client->mac_addr_len, &client->ia_na.id); + if (r < 0) + return r; + + return 0; +} + +static int client_parse_message(sd_dhcp6_client *client, + DHCP6Message *message, size_t len, + sd_dhcp6_lease *lease) { + int r; + uint8_t *optval, *option, *id = NULL; + uint16_t optcode, status; + size_t optlen, id_len; + bool clientid = false; + be32_t iaid_lease; + + option = (uint8_t *)message + sizeof(DHCP6Message); + len -= sizeof(DHCP6Message); + + while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen, + &optval)) >= 0) { + switch (optcode) { + case DHCP6_OPTION_CLIENTID: + if (clientid) { + log_dhcp6_client(client, "%s contains multiple clientids", + dhcp6_message_type_to_string(message->type)); + return -EINVAL; + } + + if (optlen != client->duid_len || + memcmp(&client->duid, optval, optlen) != 0) { + log_dhcp6_client(client, "%s DUID does not match", + dhcp6_message_type_to_string(message->type)); + + return -EINVAL; + } + clientid = true; + + break; + + case DHCP6_OPTION_SERVERID: + r = dhcp6_lease_get_serverid(lease, &id, &id_len); + if (r >= 0 && id) { + log_dhcp6_client(client, "%s contains multiple serverids", + dhcp6_message_type_to_string(message->type)); + return -EINVAL; + } + + r = dhcp6_lease_set_serverid(lease, optval, optlen); + if (r < 0) + return r; + + break; + + case DHCP6_OPTION_PREFERENCE: + if (optlen != 1) + return -EINVAL; + + r = dhcp6_lease_set_preference(lease, *optval); + if (r < 0) + return r; + + break; + + case DHCP6_OPTION_STATUS_CODE: + if (optlen < 2) + return -EINVAL; + + status = optval[0] << 8 | optval[1]; + if (status) { + log_dhcp6_client(client, "%s Status %s", + dhcp6_message_type_to_string(message->type), + dhcp6_message_status_to_string(status)); + return -EINVAL; + } + + break; + + case DHCP6_OPTION_IA_NA: + if (client->state == DHCP6_STATE_INFORMATION_REQUEST) { + log_dhcp6_client(client, "Information request ignoring IA NA option"); + + break; + } + + r = dhcp6_option_parse_ia(&optval, &optlen, optcode, + &lease->ia); + if (r < 0 && r != -ENOMSG) + return r; + + r = dhcp6_lease_get_iaid(lease, &iaid_lease); + if (r < 0) + return r; + + if (client->ia_na.id != iaid_lease) { + log_dhcp6_client(client, "%s has wrong IAID", + dhcp6_message_type_to_string(message->type)); + return -EINVAL; + } + + break; + + case DHCP6_OPTION_RAPID_COMMIT: + r = dhcp6_lease_set_rapid_commit(lease); + if (r < 0) + return r; + + break; + + case DHCP6_OPTION_DNS_SERVERS: + r = dhcp6_lease_set_dns(lease, optval, optlen); + if (r < 0) + return r; + + break; + + case DHCP6_OPTION_DOMAIN_LIST: + r = dhcp6_lease_set_domains(lease, optval, optlen); + if (r < 0) + return r; + + break; + + case DHCP6_OPTION_NTP_SERVER: + r = dhcp6_lease_set_ntp(lease, optval, optlen); + if (r < 0) + return r; + + break; + + case DHCP6_OPTION_SNTP_SERVERS: + r = dhcp6_lease_set_sntp(lease, optval, optlen); + if (r < 0) + return r; + + break; + } + + } + + if (r == -ENOMSG) + r = 0; + + if (r < 0 || !clientid) { + log_dhcp6_client(client, "%s has incomplete options", + dhcp6_message_type_to_string(message->type)); + return -EINVAL; + } + + if (client->state != DHCP6_STATE_INFORMATION_REQUEST) { + r = dhcp6_lease_get_serverid(lease, &id, &id_len); + if (r < 0) + log_dhcp6_client(client, "%s has no server id", + dhcp6_message_type_to_string(message->type)); + } + + return r; +} + +static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) { + int r; + _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; + bool rapid_commit; + + if (reply->type != DHCP6_REPLY) + return 0; + + r = dhcp6_lease_new(&lease); + if (r < 0) + return -ENOMEM; + + r = client_parse_message(client, reply, len, lease); + if (r < 0) + return r; + + if (client->state == DHCP6_STATE_SOLICITATION) { + r = dhcp6_lease_get_rapid_commit(lease, &rapid_commit); + if (r < 0) + return r; + + if (!rapid_commit) + return 0; + } + + client_set_lease(client, lease); + lease = NULL; + + return DHCP6_STATE_BOUND; +} + +static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) { + int r; + _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; + uint8_t pref_advertise = 0, pref_lease = 0; + + if (advertise->type != DHCP6_ADVERTISE) + return 0; + + r = dhcp6_lease_new(&lease); + if (r < 0) + return r; + + r = client_parse_message(client, advertise, len, lease); + if (r < 0) + return r; + + r = dhcp6_lease_get_preference(lease, &pref_advertise); + if (r < 0) + return r; + + r = dhcp6_lease_get_preference(client->lease, &pref_lease); + + if (r < 0 || pref_advertise > pref_lease) { + client_set_lease(client, lease); + lease = NULL; + r = 0; + } + + if (pref_advertise == 255 || client->retransmit_count > 1) + r = DHCP6_STATE_REQUEST; + + return r; +} + +static int client_receive_message(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + sd_dhcp6_client *client = userdata; + DHCP6_CLIENT_DONT_DESTROY(client); + _cleanup_free_ DHCP6Message *message = NULL; + int r, buflen, len; + + assert(s); + assert(client); + assert(client->event); + + r = ioctl(fd, FIONREAD, &buflen); + if (r < 0) + return -errno; + else if (buflen < 0) + /* This really should not happen */ + return -EIO; + + message = malloc(buflen); + if (!message) + return -ENOMEM; + + len = read(fd, message, buflen); + if (len < 0) { + if (errno == EAGAIN || errno == EINTR) + return 0; + + log_dhcp6_client(client, "Could not receive message from UDP socket: %m"); + + return -errno; + } else if ((size_t)len < sizeof(DHCP6Message)) + return 0; + + switch(message->type) { + case DHCP6_SOLICIT: + case DHCP6_REQUEST: + case DHCP6_CONFIRM: + case DHCP6_RENEW: + case DHCP6_REBIND: + case DHCP6_RELEASE: + case DHCP6_DECLINE: + case DHCP6_INFORMATION_REQUEST: + case DHCP6_RELAY_FORW: + case DHCP6_RELAY_REPL: + return 0; + + case DHCP6_ADVERTISE: + case DHCP6_REPLY: + case DHCP6_RECONFIGURE: + break; + + default: + log_dhcp6_client(client, "unknown message type %d", + message->type); + return 0; + } + + if (client->transaction_id != (message->transaction_id & + htobe32(0x00ffffff))) + return 0; + + switch (client->state) { + case DHCP6_STATE_INFORMATION_REQUEST: + r = client_receive_reply(client, message, len); + if (r < 0) + return 0; + + client_notify(client, SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST); + + client_start(client, DHCP6_STATE_STOPPED); + + break; + + case DHCP6_STATE_SOLICITATION: + r = client_receive_advertise(client, message, len); + + if (r == DHCP6_STATE_REQUEST) { + client_start(client, r); + + break; + } + + /* fall through for Soliciation Rapid Commit option check */ + case DHCP6_STATE_REQUEST: + case DHCP6_STATE_RENEW: + case DHCP6_STATE_REBIND: + + r = client_receive_reply(client, message, len); + if (r < 0) + return 0; + + if (r == DHCP6_STATE_BOUND) { + + r = client_start(client, DHCP6_STATE_BOUND); + if (r < 0) { + client_stop(client, r); + return 0; + } + + client_notify(client, SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE); + } + + break; + + case DHCP6_STATE_BOUND: + + break; + + case DHCP6_STATE_STOPPED: + return 0; + } + + if (r >= 0) { + log_dhcp6_client(client, "Recv %s", + dhcp6_message_type_to_string(message->type)); + } + + return 0; +} + +static int client_start(sd_dhcp6_client *client, enum DHCP6State state) { + int r; + usec_t timeout, time_now; + char time_string[FORMAT_TIMESPAN_MAX]; + + assert_return(client, -EINVAL); + assert_return(client->event, -EINVAL); + assert_return(client->index > 0, -EINVAL); + assert_return(client->state != state, -EINVAL); + + client->timeout_resend_expire = + sd_event_source_unref(client->timeout_resend_expire); + client->timeout_resend = sd_event_source_unref(client->timeout_resend); + client->retransmit_time = 0; + client->retransmit_count = 0; + + r = sd_event_now(client->event, clock_boottime_or_monotonic(), &time_now); + if (r < 0) + return r; + + switch (state) { + case DHCP6_STATE_STOPPED: + if (client->state == DHCP6_STATE_INFORMATION_REQUEST) { + client->state = DHCP6_STATE_STOPPED; + + return 0; + } + + /* fall through */ + case DHCP6_STATE_SOLICITATION: + client->state = DHCP6_STATE_SOLICITATION; + + break; + + case DHCP6_STATE_INFORMATION_REQUEST: + case DHCP6_STATE_REQUEST: + case DHCP6_STATE_RENEW: + case DHCP6_STATE_REBIND: + + client->state = state; + + break; + + case DHCP6_STATE_BOUND: + + if (client->lease->ia.lifetime_t1 == 0xffffffff || + client->lease->ia.lifetime_t2 == 0xffffffff) { + + log_dhcp6_client(client, "infinite T1 0x%08x or T2 0x%08x", + be32toh(client->lease->ia.lifetime_t1), + be32toh(client->lease->ia.lifetime_t2)); + + return 0; + } + + timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t1) * USEC_PER_SEC); + + log_dhcp6_client(client, "T1 expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC)); + + r = sd_event_add_time(client->event, + &client->lease->ia.timeout_t1, + clock_boottime_or_monotonic(), time_now + timeout, + 10 * USEC_PER_SEC, client_timeout_t1, + client); + if (r < 0) + return r; + + r = sd_event_source_set_priority(client->lease->ia.timeout_t1, + client->event_priority); + if (r < 0) + return r; + + r = sd_event_source_set_description(client->lease->ia.timeout_t1, "dhcp6-t1-timeout"); + if (r < 0) + return r; + + timeout = client_timeout_compute_random(be32toh(client->lease->ia.lifetime_t2) * USEC_PER_SEC); + + log_dhcp6_client(client, "T2 expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, timeout, USEC_PER_SEC)); + + r = sd_event_add_time(client->event, + &client->lease->ia.timeout_t2, + clock_boottime_or_monotonic(), time_now + timeout, + 10 * USEC_PER_SEC, client_timeout_t2, + client); + if (r < 0) + return r; + + r = sd_event_source_set_priority(client->lease->ia.timeout_t2, + client->event_priority); + if (r < 0) + return r; + + r = sd_event_source_set_description(client->lease->ia.timeout_t2, "dhcp6-t2-timeout"); + if (r < 0) + return r; + + client->state = state; + + return 0; + } + + client->transaction_id = random_u32() & htobe32(0x00ffffff); + client->transaction_start = time_now; + + r = sd_event_add_time(client->event, &client->timeout_resend, + clock_boottime_or_monotonic(), 0, 0, client_timeout_resend, + client); + if (r < 0) + return r; + + r = sd_event_source_set_priority(client->timeout_resend, + client->event_priority); + if (r < 0) + return r; + + r = sd_event_source_set_description(client->timeout_resend, "dhcp6-resend-timeout"); + if (r < 0) + return r; + + return 0; +} + +int sd_dhcp6_client_stop(sd_dhcp6_client *client) { + assert_return(client, -EINVAL); + + client_stop(client, SD_DHCP6_CLIENT_EVENT_STOP); + + return 0; +} + +int sd_dhcp6_client_is_running(sd_dhcp6_client *client) { + assert_return(client, -EINVAL); + + return client->state != DHCP6_STATE_STOPPED; +} + +int sd_dhcp6_client_start(sd_dhcp6_client *client) { + int r = 0; + enum DHCP6State state = DHCP6_STATE_SOLICITATION; + + assert_return(client, -EINVAL); + assert_return(client->event, -EINVAL); + assert_return(client->index > 0, -EINVAL); + assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0, -EINVAL); + + if (!IN_SET(client->state, DHCP6_STATE_STOPPED)) + return -EBUSY; + + r = client_reset(client); + if (r < 0) + return r; + + r = client_ensure_iaid(client); + if (r < 0) + return r; + + r = client_ensure_duid(client); + if (r < 0) + return r; + + r = dhcp6_network_bind_udp_socket(client->index, &client->local_address); + if (r < 0) + return r; + + client->fd = r; + + r = sd_event_add_io(client->event, &client->receive_message, + client->fd, EPOLLIN, client_receive_message, + client); + if (r < 0) + goto error; + + r = sd_event_source_set_priority(client->receive_message, + client->event_priority); + if (r < 0) + goto error; + + r = sd_event_source_set_description(client->receive_message, + "dhcp6-receive-message"); + if (r < 0) + goto error; + + if (client->information_request) + state = DHCP6_STATE_INFORMATION_REQUEST; + + log_dhcp6_client(client, "Started in %s mode", + client->information_request? "Information request": + "Managed"); + + return client_start(client, state); + +error: + client_reset(client); + return r; +} + +int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, int priority) { + int r; + + assert_return(client, -EINVAL); + assert_return(!client->event, -EBUSY); + + if (event) + client->event = sd_event_ref(event); + else { + r = sd_event_default(&client->event); + if (r < 0) + return 0; + } + + client->event_priority = priority; + + return 0; +} + +int sd_dhcp6_client_detach_event(sd_dhcp6_client *client) { + assert_return(client, -EINVAL); + + client->event = sd_event_unref(client->event); + + return 0; +} + +sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client) { + if (!client) + return NULL; + + return client->event; +} + +sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client) { + + if (!client) + return NULL; + + assert(client->n_ref >= 1); + client->n_ref++; + + return client; +} + +sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) { + + if (!client) + return NULL; + + assert(client->n_ref >= 1); + client->n_ref--; + + if (client->n_ref > 0) + return NULL; + + client_reset(client); + + sd_dhcp6_client_detach_event(client); + + free(client->req_opts); + free(client); + + return NULL; +} + +int sd_dhcp6_client_new(sd_dhcp6_client **ret) { + _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL; + size_t t; + + assert_return(ret, -EINVAL); + + client = new0(sd_dhcp6_client, 1); + if (!client) + return -ENOMEM; + + client->n_ref = 1; + + client->ia_na.type = DHCP6_OPTION_IA_NA; + + client->index = -1; + + client->fd = -1; + + client->req_opts_len = ELEMENTSOF(default_req_opts); + + client->req_opts = new0(be16_t, client->req_opts_len); + if (!client->req_opts) + return -ENOMEM; + + for (t = 0; t < client->req_opts_len; t++) + client->req_opts[t] = htobe16(default_req_opts[t]); + + *ret = client; + client = NULL; + + return 0; +} diff --git a/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c new file mode 100644 index 00000000..6a575aac --- /dev/null +++ b/src/systemd/src/libsystemd-network/sd-dhcp6-lease.c @@ -0,0 +1,414 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include + +#include "alloc-util.h" +#include "dhcp6-lease-internal.h" +#include "dhcp6-protocol.h" +#include "strv.h" +#include "util.h" + +int dhcp6_lease_clear_timers(DHCP6IA *ia) { + assert_return(ia, -EINVAL); + + ia->timeout_t1 = sd_event_source_unref(ia->timeout_t1); + ia->timeout_t2 = sd_event_source_unref(ia->timeout_t2); + + return 0; +} + +int dhcp6_lease_ia_rebind_expire(const DHCP6IA *ia, uint32_t *expire) { + DHCP6Address *addr; + uint32_t valid = 0, t; + + assert_return(ia, -EINVAL); + assert_return(expire, -EINVAL); + + LIST_FOREACH(addresses, addr, ia->addresses) { + t = be32toh(addr->iaaddr.lifetime_valid); + if (valid < t) + valid = t; + } + + t = be32toh(ia->lifetime_t2); + if (t > valid) + return -EINVAL; + + *expire = valid - t; + + return 0; +} + +DHCP6IA *dhcp6_lease_free_ia(DHCP6IA *ia) { + DHCP6Address *address; + + if (!ia) + return NULL; + + dhcp6_lease_clear_timers(ia); + + while (ia->addresses) { + address = ia->addresses; + + LIST_REMOVE(addresses, ia->addresses, address); + + free(address); + } + + return NULL; +} + +int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id, + size_t len) { + assert_return(lease, -EINVAL); + assert_return(id, -EINVAL); + + free(lease->serverid); + + lease->serverid = memdup(id, len); + if (!lease->serverid) + return -EINVAL; + + lease->serverid_len = len; + + return 0; +} + +int dhcp6_lease_get_serverid(sd_dhcp6_lease *lease, uint8_t **id, size_t *len) { + assert_return(lease, -EINVAL); + assert_return(id, -EINVAL); + assert_return(len, -EINVAL); + + *id = lease->serverid; + *len = lease->serverid_len; + + return 0; +} + +int dhcp6_lease_set_preference(sd_dhcp6_lease *lease, uint8_t preference) { + assert_return(lease, -EINVAL); + + lease->preference = preference; + + return 0; +} + +int dhcp6_lease_get_preference(sd_dhcp6_lease *lease, uint8_t *preference) { + assert_return(preference, -EINVAL); + + if (!lease) + return -EINVAL; + + *preference = lease->preference; + + return 0; +} + +int dhcp6_lease_set_rapid_commit(sd_dhcp6_lease *lease) { + assert_return(lease, -EINVAL); + + lease->rapid_commit = true; + + return 0; +} + +int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *rapid_commit) { + assert_return(lease, -EINVAL); + assert_return(rapid_commit, -EINVAL); + + *rapid_commit = lease->rapid_commit; + + return 0; +} + +int dhcp6_lease_get_iaid(sd_dhcp6_lease *lease, be32_t *iaid) { + assert_return(lease, -EINVAL); + assert_return(iaid, -EINVAL); + + *iaid = lease->ia.id; + + return 0; +} + +int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *addr, + uint32_t *lifetime_preferred, + uint32_t *lifetime_valid) { + assert_return(lease, -EINVAL); + assert_return(addr, -EINVAL); + assert_return(lifetime_preferred, -EINVAL); + assert_return(lifetime_valid, -EINVAL); + + if (!lease->addr_iter) + return -ENOMSG; + + memcpy(addr, &lease->addr_iter->iaaddr.address, + sizeof(struct in6_addr)); + *lifetime_preferred = + be32toh(lease->addr_iter->iaaddr.lifetime_preferred); + *lifetime_valid = be32toh(lease->addr_iter->iaaddr.lifetime_valid); + + lease->addr_iter = lease->addr_iter->addresses_next; + + return 0; +} + +void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease) { + if (lease) + lease->addr_iter = lease->ia.addresses; +} + +int dhcp6_lease_set_dns(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) { + int r; + + assert_return(lease, -EINVAL); + assert_return(optval, -EINVAL); + + if (!optlen) + return 0; + + r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->dns, + lease->dns_count, + &lease->dns_allocated); + if (r < 0) { + log_dhcp6_client(client, "Invalid DNS server option: %s", + strerror(-r)); + + return r; + } + + lease->dns_count = r; + + return 0; +} + +int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, struct in6_addr **addrs) { + assert_return(lease, -EINVAL); + assert_return(addrs, -EINVAL); + + if (lease->dns_count) { + *addrs = lease->dns; + return lease->dns_count; + } + + return -ENOENT; +} + +int dhcp6_lease_set_domains(sd_dhcp6_lease *lease, uint8_t *optval, + size_t optlen) { + int r; + char **domains; + + assert_return(lease, -EINVAL); + assert_return(optval, -EINVAL); + + if (!optlen) + return 0; + + r = dhcp6_option_parse_domainname(optval, optlen, &domains); + if (r < 0) + return 0; + + free(lease->domains); + lease->domains = domains; + lease->domains_count = r; + + return r; +} + +int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains) { + assert_return(lease, -EINVAL); + assert_return(domains, -EINVAL); + + if (lease->domains_count) { + *domains = lease->domains; + return lease->domains_count; + } + + return -ENOENT; +} + +int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) { + int r; + uint16_t subopt; + size_t sublen; + uint8_t *subval; + + assert_return(lease, -EINVAL); + assert_return(optval, -EINVAL); + + free(lease->ntp); + lease->ntp_count = 0; + lease->ntp_allocated = 0; + + while ((r = dhcp6_option_parse(&optval, &optlen, &subopt, &sublen, + &subval)) >= 0) { + int s; + char **servers; + + switch(subopt) { + case DHCP6_NTP_SUBOPTION_SRV_ADDR: + case DHCP6_NTP_SUBOPTION_MC_ADDR: + if (sublen != 16) + return 0; + + s = dhcp6_option_parse_ip6addrs(subval, sublen, + &lease->ntp, + lease->ntp_count, + &lease->ntp_allocated); + if (s < 0) + return s; + + lease->ntp_count = s; + + break; + + case DHCP6_NTP_SUBOPTION_SRV_FQDN: + r = dhcp6_option_parse_domainname(subval, sublen, + &servers); + if (r < 0) + return 0; + + lease->ntp_fqdn = strv_free(lease->ntp_fqdn); + lease->ntp_fqdn = servers; + lease->ntp_fqdn_count = r; + + break; + } + } + + if (r != -ENOMSG) + return r; + + return 0; +} + +int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) { + int r; + + assert_return(lease, -EINVAL); + assert_return(optval, -EINVAL); + + if (!optlen) + return 0; + + if (lease->ntp || lease->ntp_fqdn) { + log_dhcp6_client(client, "NTP information already provided"); + + return 0; + } + + log_dhcp6_client(client, "Using deprecated SNTP information"); + + r = dhcp6_option_parse_ip6addrs(optval, optlen, &lease->ntp, + lease->ntp_count, + &lease->ntp_allocated); + if (r < 0) { + log_dhcp6_client(client, "Invalid SNTP server option: %s", + strerror(-r)); + + return r; + } + + lease->ntp_count = r; + + return 0; +} + +int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, + struct in6_addr **addrs) { + assert_return(lease, -EINVAL); + assert_return(addrs, -EINVAL); + + if (lease->ntp_count) { + *addrs = lease->ntp; + return lease->ntp_count; + } + + return -ENOENT; +} + +int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn) { + assert_return(lease, -EINVAL); + assert_return(ntp_fqdn, -EINVAL); + + if (lease->ntp_fqdn_count) { + *ntp_fqdn = lease->ntp_fqdn; + return lease->ntp_fqdn_count; + } + + return -ENOENT; +} + +sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease) { + + if (!lease) + return NULL; + + assert(lease->n_ref >= 1); + lease->n_ref++; + + return lease; +} + +sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease) { + + if (!lease) + return NULL; + + assert(lease->n_ref >= 1); + lease->n_ref--; + + if (lease->n_ref > 0) + return NULL; + + free(lease->serverid); + dhcp6_lease_free_ia(&lease->ia); + + free(lease->dns); + + lease->domains = strv_free(lease->domains); + + free(lease->ntp); + + lease->ntp_fqdn = strv_free(lease->ntp_fqdn); + free(lease); + + return NULL; +} + +int dhcp6_lease_new(sd_dhcp6_lease **ret) { + sd_dhcp6_lease *lease; + + lease = new0(sd_dhcp6_lease, 1); + if (!lease) + return -ENOMEM; + + lease->n_ref = 1; + + LIST_HEAD_INIT(lease->ia.addresses); + + *ret = lease; + return 0; +} diff --git a/src/systemd/src/libsystemd-network/sd-ipv4acd.c b/src/systemd/src/libsystemd-network/sd-ipv4acd.c new file mode 100644 index 00000000..99e663c1 --- /dev/null +++ b/src/systemd/src/libsystemd-network/sd-ipv4acd.c @@ -0,0 +1,529 @@ +/*** + This file is part of systemd. + + Copyright (C) 2014 Axis Communications AB. All rights reserved. + Copyright (C) 2015 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include + +#include "sd-ipv4acd.h" + +#include "alloc-util.h" +#include "arp-util.h" +#include "fd-util.h" +#include "in-addr-util.h" +#include "list.h" +#include "random-util.h" +#include "refcnt.h" +#include "siphash24.h" +#include "util.h" + +/* Constants from the RFC */ +#define PROBE_WAIT 1 +#define PROBE_NUM 3 +#define PROBE_MIN 1 +#define PROBE_MAX 2 +#define ANNOUNCE_WAIT 2 +#define ANNOUNCE_NUM 2 +#define ANNOUNCE_INTERVAL 2 +#define MAX_CONFLICTS 10 +#define RATE_LIMIT_INTERVAL 60 +#define DEFEND_INTERVAL 10 + +#define IPV4ACD_NETWORK 0xA9FE0000L +#define IPV4ACD_NETMASK 0xFFFF0000L + +#define log_ipv4acd_full(ll, level, error, fmt, ...) log_internal(level, error, __FILE__, __LINE__, __func__, "ACD: " fmt, ##__VA_ARGS__) + +#define log_ipv4acd_debug(ll, ...) log_ipv4acd_full(ll, LOG_DEBUG, 0, ##__VA_ARGS__) +#define log_ipv4acd_info(ll, ...) log_ipv4acd_full(ll, LOG_INFO, 0, ##__VA_ARGS__) +#define log_ipv4acd_notice(ll, ...) log_ipv4acd_full(ll, LOG_NOTICE, 0, ##__VA_ARGS__) +#define log_ipv4acd_warning(ll, ...) log_ipv4acd_full(ll, LOG_WARNING, 0, ##__VA_ARGS__) +#define log_ipv4acd_error(ll, ...) log_ipv4acd_full(ll, LOG_ERR, 0, ##__VA_ARGS__) + +#define log_ipv4acd_debug_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_DEBUG, error, ##__VA_ARGS__) +#define log_ipv4acd_info_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_INFO, error, ##__VA_ARGS__) +#define log_ipv4acd_notice_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_NOTICE, error, ##__VA_ARGS__) +#define log_ipv4acd_warning_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_WARNING, error, ##__VA_ARGS__) +#define log_ipv4acd_error_errno(ll, error, ...) log_ipv4acd_full(ll, LOG_ERR, error, ##__VA_ARGS__) + +typedef enum IPv4ACDState { + IPV4ACD_STATE_INIT, + IPV4ACD_STATE_WAITING_PROBE, + IPV4ACD_STATE_PROBING, + IPV4ACD_STATE_WAITING_ANNOUNCE, + IPV4ACD_STATE_ANNOUNCING, + IPV4ACD_STATE_RUNNING, + _IPV4ACD_STATE_MAX, + _IPV4ACD_STATE_INVALID = -1 +} IPv4ACDState; + +struct sd_ipv4acd { + RefCount n_ref; + + IPv4ACDState state; + int index; + int fd; + int iteration; + int conflict; + sd_event_source *receive_message; + sd_event_source *timer; + usec_t defend_window; + be32_t address; + /* External */ + struct ether_addr mac_addr; + sd_event *event; + int event_priority; + sd_ipv4acd_cb_t cb; + void* userdata; +}; + +sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll) { + if (ll) + assert_se(REFCNT_INC(ll->n_ref) >= 2); + + return ll; +} + +sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll) { + if (!ll || REFCNT_DEC(ll->n_ref) > 0) + return NULL; + + ll->receive_message = sd_event_source_unref(ll->receive_message); + ll->fd = safe_close(ll->fd); + + ll->timer = sd_event_source_unref(ll->timer); + + sd_ipv4acd_detach_event(ll); + + free(ll); + + return NULL; +} + +int sd_ipv4acd_new(sd_ipv4acd **ret) { + _cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *ll = NULL; + + assert_return(ret, -EINVAL); + + ll = new0(sd_ipv4acd, 1); + if (!ll) + return -ENOMEM; + + ll->n_ref = REFCNT_INIT; + ll->state = IPV4ACD_STATE_INIT; + ll->index = -1; + ll->fd = -1; + + *ret = ll; + ll = NULL; + + return 0; +} + +static void ipv4acd_set_state(sd_ipv4acd *ll, IPv4ACDState st, bool reset_counter) { + + assert(ll); + assert(st < _IPV4ACD_STATE_MAX); + + if (st == ll->state && !reset_counter) + ll->iteration++; + else { + ll->state = st; + ll->iteration = 0; + } +} + +static void ipv4acd_client_notify(sd_ipv4acd *ll, int event) { + assert(ll); + + if (ll->cb) + ll->cb(ll, event, ll->userdata); +} + +static void ipv4acd_stop(sd_ipv4acd *ll) { + assert(ll); + + ll->receive_message = sd_event_source_unref(ll->receive_message); + ll->fd = safe_close(ll->fd); + + ll->timer = sd_event_source_unref(ll->timer); + + log_ipv4acd_debug(ll, "STOPPED"); + + ipv4acd_set_state (ll, IPV4ACD_STATE_INIT, true); +} + +int sd_ipv4acd_stop(sd_ipv4acd *ll) { + assert_return(ll, -EINVAL); + + ipv4acd_stop(ll); + + ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_STOP); + + return 0; +} + +static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata); + +static int ipv4acd_set_next_wakeup(sd_ipv4acd *ll, int sec, int random_sec) { + _cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL; + usec_t next_timeout; + usec_t time_now; + int r; + + assert(sec >= 0); + assert(random_sec >= 0); + assert(ll); + + next_timeout = sec * USEC_PER_SEC; + + if (random_sec) + next_timeout += random_u32() % (random_sec * USEC_PER_SEC); + + assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) >= 0); + + r = sd_event_add_time(ll->event, &timer, clock_boottime_or_monotonic(), + time_now + next_timeout, 0, ipv4acd_on_timeout, ll); + if (r < 0) + return r; + + r = sd_event_source_set_priority(timer, ll->event_priority); + if (r < 0) + return r; + + r = sd_event_source_set_description(timer, "ipv4acd-timer"); + if (r < 0) + return r; + + ll->timer = sd_event_source_unref(ll->timer); + ll->timer = timer; + timer = NULL; + + return 0; +} + +static bool ipv4acd_arp_conflict(sd_ipv4acd *ll, struct ether_arp *arp) { + assert(ll); + assert(arp); + + /* see the BPF */ + if (memcmp(arp->arp_spa, &ll->address, sizeof(ll->address)) == 0) + return true; + + /* the TPA matched instead of the SPA, this is not a conflict */ + return false; +} + +static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) { + sd_ipv4acd *ll = userdata; + int r = 0; + + assert(ll); + + switch (ll->state) { + case IPV4ACD_STATE_INIT: + + ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_PROBE, true); + + if (ll->conflict >= MAX_CONFLICTS) { + log_ipv4acd_notice(ll, "Max conflicts reached, delaying by %us", RATE_LIMIT_INTERVAL); + r = ipv4acd_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT); + if (r < 0) + goto out; + + ll->conflict = 0; + } else { + r = ipv4acd_set_next_wakeup(ll, 0, PROBE_WAIT); + if (r < 0) + goto out; + } + + break; + case IPV4ACD_STATE_WAITING_PROBE: + case IPV4ACD_STATE_PROBING: + /* Send a probe */ + r = arp_send_probe(ll->fd, ll->index, ll->address, &ll->mac_addr); + if (r < 0) { + log_ipv4acd_error_errno(ll, r, "Failed to send ARP probe: %m"); + goto out; + } else { + _cleanup_free_ char *address = NULL; + union in_addr_union addr = { .in.s_addr = ll->address }; + + r = in_addr_to_string(AF_INET, &addr, &address); + if (r >= 0) + log_ipv4acd_debug(ll, "Probing %s", address); + } + + if (ll->iteration < PROBE_NUM - 2) { + ipv4acd_set_state(ll, IPV4ACD_STATE_PROBING, false); + + r = ipv4acd_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN)); + if (r < 0) + goto out; + } else { + ipv4acd_set_state(ll, IPV4ACD_STATE_WAITING_ANNOUNCE, true); + + r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_WAIT, 0); + if (r < 0) + goto out; + } + + break; + + case IPV4ACD_STATE_ANNOUNCING: + if (ll->iteration >= ANNOUNCE_NUM - 1) { + ipv4acd_set_state(ll, IPV4ACD_STATE_RUNNING, false); + + break; + } + case IPV4ACD_STATE_WAITING_ANNOUNCE: + /* Send announcement packet */ + r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr); + if (r < 0) { + log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m"); + goto out; + } else + log_ipv4acd_debug(ll, "ANNOUNCE"); + + ipv4acd_set_state(ll, IPV4ACD_STATE_ANNOUNCING, false); + + r = ipv4acd_set_next_wakeup(ll, ANNOUNCE_INTERVAL, 0); + if (r < 0) + goto out; + + if (ll->iteration == 0) { + ll->conflict = 0; + ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_BIND); + } + + break; + default: + assert_not_reached("Invalid state."); + } + +out: + if (r < 0) + sd_ipv4acd_stop(ll); + + return 1; +} + +static void ipv4acd_on_conflict(sd_ipv4acd *ll) { + _cleanup_free_ char *address = NULL; + union in_addr_union addr = { .in.s_addr = ll->address }; + int r; + + assert(ll); + + ll->conflict++; + + r = in_addr_to_string(AF_INET, &addr, &address); + if (r >= 0) + log_ipv4acd_debug(ll, "Conflict on %s (%u)", address, ll->conflict); + + ipv4acd_stop(ll); + + ipv4acd_client_notify(ll, SD_IPV4ACD_EVENT_CONFLICT); +} + +static int ipv4acd_on_packet(sd_event_source *s, int fd, + uint32_t revents, void *userdata) { + sd_ipv4acd *ll = userdata; + struct ether_arp packet; + int r; + + assert(ll); + assert(fd >= 0); + + r = read(fd, &packet, sizeof(struct ether_arp)); + if (r < (int) sizeof(struct ether_arp)) + goto out; + + switch (ll->state) { + case IPV4ACD_STATE_ANNOUNCING: + case IPV4ACD_STATE_RUNNING: + if (ipv4acd_arp_conflict(ll, &packet)) { + usec_t ts; + + assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &ts) >= 0); + + /* Defend address */ + if (ts > ll->defend_window) { + ll->defend_window = ts + DEFEND_INTERVAL * USEC_PER_SEC; + r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr); + if (r < 0) { + log_ipv4acd_error_errno(ll, r, "Failed to send ARP announcement: %m"); + goto out; + } else + log_ipv4acd_debug(ll, "DEFEND"); + + } else + ipv4acd_on_conflict(ll); + } + + break; + case IPV4ACD_STATE_WAITING_PROBE: + case IPV4ACD_STATE_PROBING: + case IPV4ACD_STATE_WAITING_ANNOUNCE: + /* BPF ensures this packet indicates a conflict */ + ipv4acd_on_conflict(ll); + + break; + default: + assert_not_reached("Invalid state."); + } + +out: + if (r < 0) + sd_ipv4acd_stop(ll); + + return 1; +} + +int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index) { + assert_return(ll, -EINVAL); + assert_return(interface_index > 0, -EINVAL); + assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY); + + ll->index = interface_index; + + return 0; +} + +int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr) { + assert_return(ll, -EINVAL); + assert_return(addr, -EINVAL); + assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY); + + memcpy(&ll->mac_addr, addr, ETH_ALEN); + + return 0; +} + +int sd_ipv4acd_detach_event(sd_ipv4acd *ll) { + assert_return(ll, -EINVAL); + + ll->event = sd_event_unref(ll->event); + + return 0; +} + +int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority) { + int r; + + assert_return(ll, -EINVAL); + assert_return(!ll->event, -EBUSY); + + if (event) + ll->event = sd_event_ref(event); + else { + r = sd_event_default(&ll->event); + if (r < 0) + return r; + } + + ll->event_priority = priority; + + return 0; +} + +int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata) { + assert_return(ll, -EINVAL); + + ll->cb = cb; + ll->userdata = userdata; + + return 0; +} + +int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address){ + assert_return(ll, -EINVAL); + assert_return(address, -EINVAL); + assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY); + + ll->address = address->s_addr; + + return 0; +} + +int sd_ipv4acd_is_running(sd_ipv4acd *ll) { + assert_return(ll, false); + + return ll->state != IPV4ACD_STATE_INIT; +} + +static bool ether_addr_is_nul(const struct ether_addr *addr) { + const struct ether_addr nul_addr = {}; + + assert(addr); + + return memcmp(addr, &nul_addr, sizeof(struct ether_addr)) == 0; +} + +#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2) + +int sd_ipv4acd_start(sd_ipv4acd *ll) { + int r; + + assert_return(ll, -EINVAL); + assert_return(ll->event, -EINVAL); + assert_return(ll->index > 0, -EINVAL); + assert_return(ll->address != 0, -EINVAL); + assert_return(!ether_addr_is_nul(&ll->mac_addr), -EINVAL); + assert_return(ll->state == IPV4ACD_STATE_INIT, -EBUSY); + + ll->defend_window = 0; + + r = arp_network_bind_raw_socket(ll->index, ll->address, &ll->mac_addr); + if (r < 0) + goto out; + + ll->fd = safe_close(ll->fd); + ll->fd = r; + + r = sd_event_add_io(ll->event, &ll->receive_message, ll->fd, + EPOLLIN, ipv4acd_on_packet, ll); + if (r < 0) + goto out; + + r = sd_event_source_set_priority(ll->receive_message, ll->event_priority); + if (r < 0) + goto out; + + r = sd_event_source_set_description(ll->receive_message, "ipv4acd-receive-message"); + if (r < 0) + goto out; + + r = ipv4acd_set_next_wakeup(ll, 0, 0); + if (r < 0) + goto out; +out: + if (r < 0) { + ipv4acd_stop(ll); + return r; + } + + return 0; +} diff --git a/src/systemd/src/libsystemd-network/sd-ipv4ll.c b/src/systemd/src/libsystemd-network/sd-ipv4ll.c new file mode 100644 index 00000000..119d00fc --- /dev/null +++ b/src/systemd/src/libsystemd-network/sd-ipv4ll.c @@ -0,0 +1,366 @@ +/*** + This file is part of systemd. + + Copyright (C) 2014 Axis Communications AB. All rights reserved. + Copyright (C) 2015 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include + +#include "sd-ipv4acd.h" +#include "sd-ipv4ll.h" + +#include "alloc-util.h" +#include "in-addr-util.h" +#include "list.h" +#include "random-util.h" +#include "refcnt.h" +#include "siphash24.h" +#include "sparse-endian.h" +#include "util.h" + +#define IPV4LL_NETWORK 0xA9FE0000L +#define IPV4LL_NETMASK 0xFFFF0000L + +#define IPV4LL_DONT_DESTROY(ll) \ + _cleanup_(sd_ipv4ll_unrefp) _unused_ sd_ipv4ll *_dont_destroy_##ll = sd_ipv4ll_ref(ll) + +struct sd_ipv4ll { + unsigned n_ref; + + sd_ipv4acd *acd; + be32_t address; /* the address pushed to ACD */ + struct random_data *random_data; + char *random_data_state; + + /* External */ + be32_t claimed_address; + sd_ipv4ll_cb_t cb; + void* userdata; +}; + +sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) { + if (!ll) + return NULL; + + assert(ll->n_ref >= 1); + ll->n_ref++; + + return ll; +} + +sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) { + if (!ll) + return NULL; + + assert(ll->n_ref >= 1); + ll->n_ref--; + + if (ll->n_ref > 0) + return NULL; + + sd_ipv4acd_unref(ll->acd); + + free(ll->random_data); + free(ll->random_data_state); + free(ll); + + return NULL; +} + +static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata); + +int sd_ipv4ll_new(sd_ipv4ll **ret) { + _cleanup_(sd_ipv4ll_unrefp) sd_ipv4ll *ll = NULL; + int r; + + assert_return(ret, -EINVAL); + + ll = new0(sd_ipv4ll, 1); + if (!ll) + return -ENOMEM; + + ll->n_ref = 1; + + r = sd_ipv4acd_new(&ll->acd); + if (r < 0) + return r; + + r = sd_ipv4acd_set_callback(ll->acd, ipv4ll_on_acd, ll); + if (r < 0) + return r; + + *ret = ll; + ll = NULL; + + return 0; +} + +int sd_ipv4ll_stop(sd_ipv4ll *ll) { + int r; + + assert_return(ll, -EINVAL); + + r = sd_ipv4acd_stop(ll->acd); + if (r < 0) + return r; + + return 0; +} + +int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index) { + assert_return(ll, -EINVAL); + + return sd_ipv4acd_set_index(ll->acd, interface_index); +} + +#define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2) + +int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) { + int r; + + assert_return(ll, -EINVAL); + + if (!ll->random_data) { + uint64_t seed; + + /* If no random data is set, generate some from the MAC */ + seed = siphash24(&addr->ether_addr_octet, ETH_ALEN, HASH_KEY.bytes); + + assert_cc(sizeof(unsigned) <= 8); + + r = sd_ipv4ll_set_address_seed(ll, (unsigned) htole64(seed)); + if (r < 0) + return r; + } + + return sd_ipv4acd_set_mac(ll->acd, addr); +} + +int sd_ipv4ll_detach_event(sd_ipv4ll *ll) { + assert_return(ll, -EINVAL); + + return sd_ipv4acd_detach_event(ll->acd); +} + +int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority) { + int r; + + assert_return(ll, -EINVAL); + + r = sd_ipv4acd_attach_event(ll->acd, event, priority); + if (r < 0) + return r; + + return 0; +} + +int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata) { + assert_return(ll, -EINVAL); + + ll->cb = cb; + ll->userdata = userdata; + + return 0; +} + +int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address){ + assert_return(ll, -EINVAL); + assert_return(address, -EINVAL); + + if (ll->claimed_address == 0) + return -ENOENT; + + address->s_addr = ll->claimed_address; + + return 0; +} + +int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed) { + _cleanup_free_ struct random_data *random_data = NULL; + _cleanup_free_ char *random_data_state = NULL; + int r; + + assert_return(ll, -EINVAL); + + random_data = new0(struct random_data, 1); + if (!random_data) + return -ENOMEM; + + random_data_state = new0(char, 128); + if (!random_data_state) + return -ENOMEM; + + r = initstate_r(seed, random_data_state, 128, random_data); + if (r < 0) + return r; + + free(ll->random_data); + ll->random_data = random_data; + random_data = NULL; + + free(ll->random_data_state); + ll->random_data_state = random_data_state; + random_data_state = NULL; + + return 0; +} + +int sd_ipv4ll_is_running(sd_ipv4ll *ll) { + assert_return(ll, false); + + return sd_ipv4acd_is_running(ll->acd); +} + +static bool ipv4ll_address_is_valid(const struct in_addr *address) { + uint32_t addr; + + assert(address); + + if (!in_addr_is_link_local(AF_INET, (const union in_addr_union *) address)) + return false; + + addr = be32toh(address->s_addr); + + if ((addr & 0x0000FF00) == 0x0000 || + (addr & 0x0000FF00) == 0xFF00) + return false; + + return true; +} + +int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) { + int r; + + assert_return(ll, -EINVAL); + assert_return(address, -EINVAL); + assert_return(ipv4ll_address_is_valid(address), -EINVAL); + + r = sd_ipv4acd_set_address(ll->acd, address); + if (r < 0) + return r; + + ll->address = address->s_addr; + + return 0; +} + +static int ipv4ll_pick_address(sd_ipv4ll *ll) { + struct in_addr in_addr; + be32_t addr; + int r; + int32_t random; + + assert(ll); + assert(ll->random_data); + + do { + r = random_r(ll->random_data, &random); + if (r < 0) + return r; + addr = htonl((random & 0x0000FFFF) | IPV4LL_NETWORK); + } while (addr == ll->address || + (ntohl(addr) & 0x0000FF00) == 0x0000 || + (ntohl(addr) & 0x0000FF00) == 0xFF00); + + in_addr.s_addr = addr; + + r = sd_ipv4ll_set_address(ll, &in_addr); + if (r < 0) + return r; + + return 0; +} + +int sd_ipv4ll_start(sd_ipv4ll *ll) { + int r; + + assert_return(ll, -EINVAL); + assert_return(ll->random_data, -EINVAL); + + if (ll->address == 0) { + r = ipv4ll_pick_address(ll); + if (r < 0) + return r; + } + + r = sd_ipv4acd_start(ll->acd); + if (r < 0) + return r; + + return 0; +} + +static void ipv4ll_client_notify(sd_ipv4ll *ll, int event) { + assert(ll); + + if (ll->cb) + ll->cb(ll, event, ll->userdata); +} + +void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) { + sd_ipv4ll *ll = userdata; + IPV4LL_DONT_DESTROY(ll); + int r; + + assert(acd); + assert(ll); + + switch (event) { + case SD_IPV4ACD_EVENT_STOP: + ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP); + + ll->claimed_address = 0; + + break; + case SD_IPV4ACD_EVENT_BIND: + ll->claimed_address = ll->address; + ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_BIND); + + break; + case SD_IPV4ACD_EVENT_CONFLICT: + /* if an address was already bound we must call up to the + user to handle this, otherwise we just try again */ + if (ll->claimed_address != 0) { + ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_CONFLICT); + + ll->claimed_address = 0; + } else { + r = ipv4ll_pick_address(ll); + if (r < 0) + goto error; + + r = sd_ipv4acd_start(ll->acd); + if (r < 0) + goto error; + } + + break; + default: + assert_not_reached("Invalid IPv4ACD event."); + } + + return; + +error: + ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP); +} diff --git a/src/systemd/src/libsystemd-network/sd-lldp.c b/src/systemd/src/libsystemd-network/sd-lldp.c new file mode 100644 index 00000000..882f130a --- /dev/null +++ b/src/systemd/src/libsystemd-network/sd-lldp.c @@ -0,0 +1,760 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014 Susant Sahani + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include + +#include "sd-lldp.h" + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "hashmap.h" +#include "lldp-internal.h" +#include "lldp-port.h" +#include "lldp-tlv.h" +#include "prioq.h" +#include "siphash24.h" +#include "string-util.h" + +typedef enum LLDPAgentRXState { + LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL = 4, + LLDP_AGENT_RX_DELETE_AGED_INFO, + LLDP_AGENT_RX_LLDP_INITIALIZE, + LLDP_AGENT_RX_WAIT_FOR_FRAME, + LLDP_AGENT_RX_RX_FRAME, + LLDP_AGENT_RX_DELETE_INFO, + LLDP_AGENT_RX_UPDATE_INFO, + _LLDP_AGENT_RX_STATE_MAX, + _LLDP_AGENT_RX_INVALID = -1, +} LLDPAgentRXState; + +/* Section 10.5.2.2 Reception counters */ +struct lldp_agent_statistics { + uint64_t stats_ageouts_total; + uint64_t stats_frames_discarded_total; + uint64_t stats_frames_in_errors_total; + uint64_t stats_frames_in_total; + uint64_t stats_tlvs_discarded_total; + uint64_t stats_tlvs_unrecognized_total; +}; + +struct sd_lldp { + lldp_port *port; + + Prioq *by_expiry; + Hashmap *neighbour_mib; + + sd_lldp_cb_t cb; + + void *userdata; + + LLDPAgentRXState rx_state; + lldp_agent_statistics statistics; +}; + +static void chassis_id_hash_func(const void *p, struct siphash *state) { + const lldp_chassis_id *id = p; + + assert(id); + assert(id->data); + + siphash24_compress(&id->length, sizeof(id->length), state); + siphash24_compress(id->data, id->length, state); +} + +static int chassis_id_compare_func(const void *_a, const void *_b) { + const lldp_chassis_id *a, *b; + + a = _a; + b = _b; + + assert(!a->length || a->data); + assert(!b->length || b->data); + + if (a->type != b->type) + return -1; + + if (a->length != b->length) + return a->length < b->length ? -1 : 1; + + return memcmp(a->data, b->data, a->length); +} + +static const struct hash_ops chassis_id_hash_ops = { + .hash = chassis_id_hash_func, + .compare = chassis_id_compare_func +}; + +static void lldp_mib_delete_objects(sd_lldp *lldp); +static void lldp_set_state(sd_lldp *lldp, LLDPAgentRXState state); +static void lldp_run_state_machine(sd_lldp *ll); + +static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) { + int r; + + assert(lldp); + assert(tlv); + + /* Remove expired packets */ + if (prioq_size(lldp->by_expiry) > 0) { + + lldp_set_state(lldp, LLDP_AGENT_RX_DELETE_INFO); + + lldp_mib_delete_objects(lldp); + } + + r = lldp_mib_add_objects(lldp->by_expiry, lldp->neighbour_mib, tlv); + if (r < 0) + goto out; + + lldp_set_state(lldp, LLDP_AGENT_RX_UPDATE_INFO); + + log_lldp("Packet added. MIB size: %d , PQ size: %d", + hashmap_size(lldp->neighbour_mib), + prioq_size(lldp->by_expiry)); + + lldp->statistics.stats_frames_in_total ++; + + out: + if (r < 0) + log_lldp("Receive frame failed: %s", strerror(-r)); + + lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME); + + return 0; +} + +/* 10.3.2 LLDPDU validation: rxProcessFrame() */ +int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { + bool system_description = false, system_name = false, chassis_id = false; + bool malformed = false, port_id = false, ttl = false, end = false; + uint16_t type, len, i, l, t; + lldp_port *port; + uint8_t *p, *q; + sd_lldp *lldp; + int r; + + assert(tlv); + assert(length > 0); + + port = (lldp_port *) tlv->userdata; + lldp = (sd_lldp *) port->userdata; + + if (lldp->port->status == LLDP_PORT_STATUS_DISABLED) { + log_lldp("Port: %s is disabled. Dropping.", lldp->port->ifname); + goto out; + } + + lldp_set_state(lldp, LLDP_AGENT_RX_RX_FRAME); + + p = tlv->pdu; + p += sizeof(struct ether_header); + + for (i = 1, l = 0; l <= length; i++) { + + memcpy(&t, p, sizeof(uint16_t)); + + type = ntohs(t) >> 9; + len = ntohs(t) & 0x01ff; + + if (type == LLDP_TYPE_END) { + if (len != 0) { + log_lldp("TLV type end must be length 0 (not %d). Dropping.", len); + + malformed = true; + goto out; + } + + end = true; + + break; + } else if (type >=_LLDP_TYPE_MAX) { + log_lldp("TLV type: %d not recognized. Dropping.", type); + + malformed = true; + goto out; + } + + /* skip type and length encoding */ + p += 2; + q = p; + + p += len; + l += (len + 2); + + if (i <= 3) { + if (i != type) { + log_lldp("TLV missing or out of order. Dropping."); + + malformed = true; + goto out; + } + } + + switch(type) { + case LLDP_TYPE_CHASSIS_ID: + + if (len < 2) { + log_lldp("Received malformed Chassis ID TLV length: %d. Dropping.", len); + + malformed = true; + goto out; + } + + if (chassis_id) { + log_lldp("Duplicate Chassis ID TLV found. Dropping."); + + malformed = true; + goto out; + } + + /* Look what subtype it has */ + if (*q == LLDP_CHASSIS_SUBTYPE_RESERVED || *q > LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED) { + log_lldp("Unknown subtype: %d found in Chassis ID TLV. Dropping.", *q); + + malformed = true; + goto out; + + } + + chassis_id = true; + + break; + case LLDP_TYPE_PORT_ID: + + if (len < 2) { + log_lldp("Received malformed Port ID TLV length: %d. Dropping.", len); + + malformed = true; + goto out; + } + + if (port_id) { + log_lldp("Duplicate Port ID TLV found. Dropping."); + + malformed = true; + goto out; + } + + /* Look what subtype it has */ + if (*q == LLDP_PORT_SUBTYPE_RESERVED || *q > LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED) { + log_lldp("Unknown subtype: %d found in Port ID TLV. Dropping.", *q); + + malformed = true; + goto out; + + } + + port_id = true; + + break; + case LLDP_TYPE_TTL: + + if(len != 2) { + log_lldp("Received invalid TTL TLV lenth: %d. Dropping.", len); + + malformed = true; + goto out; + } + + if (ttl) { + log_lldp("Duplicate TTL TLV found. Dropping."); + + malformed = true; + goto out; + } + + ttl = true; + + break; + case LLDP_TYPE_SYSTEM_NAME: + + /* According to RFC 1035 the length of a FQDN is limited to 255 characters */ + if (len > 255) { + log_lldp("Received invalid system name length: %d. Dropping.", len); + malformed = true; + goto out; + } + + if (system_name) { + log_lldp("Duplicate system name found. Dropping."); + malformed = true; + goto out; + } + + system_name = true; + + break; + case LLDP_TYPE_SYSTEM_DESCRIPTION: + + /* 0 <= n <= 255 octets */ + if (len > 255) { + log_lldp("Received invalid system description length: %d. Dropping.", len); + malformed = true; + goto out; + } + + if (system_description) { + log_lldp("Duplicate system description found. Dropping."); + malformed = true; + goto out; + } + + system_description = true; + break; + default: + + if (len == 0) { + log_lldp("TLV type: %d length 0 received. Dropping.", type); + + malformed = true; + goto out; + } + break; + } + } + + if(!chassis_id || !port_id || !ttl || !end) { + log_lldp("One or more mandatory TLV missing. Dropping."); + + malformed = true; + goto out; + + } + + r = tlv_packet_parse_pdu(tlv, length); + if (r < 0) { + log_lldp("Failed to parse the TLV. Dropping."); + + malformed = true; + goto out; + } + + return lldp_receive_frame(lldp, tlv); + + out: + lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME); + + if (malformed) { + lldp->statistics.stats_frames_discarded_total ++; + lldp->statistics.stats_frames_in_errors_total ++; + } + + sd_lldp_packet_unref(tlv); + + return 0; +} + +static int ttl_expiry_item_prioq_compare_func(const void *a, const void *b) { + const lldp_neighbour_port *p = a, *q = b; + + if (p->until < q->until) + return -1; + + if (p->until > q->until) + return 1; + + return 0; +} + +static void lldp_set_state(sd_lldp *lldp, LLDPAgentRXState state) { + + assert(lldp); + assert(state < _LLDP_AGENT_RX_STATE_MAX); + + lldp->rx_state = state; + + lldp_run_state_machine(lldp); +} + +static void lldp_run_state_machine(sd_lldp *lldp) { + if (!lldp->cb) + return; + + switch (lldp->rx_state) { + case LLDP_AGENT_RX_UPDATE_INFO: + lldp->cb(lldp, SD_LLDP_EVENT_UPDATE_INFO, lldp->userdata); + break; + default: + break; + } +} + +/* 10.5.5.2.1 mibDeleteObjects () + * The mibDeleteObjects () procedure deletes all information in the LLDP remote + * systems MIB associated with the MSAP identifier if an LLDPDU is received with + * an rxTTL value of zero (see 10.3.2) or the timing counter rxInfoTTL expires. */ + +static void lldp_mib_delete_objects(sd_lldp *lldp) { + lldp_neighbour_port *p; + usec_t t = 0; + + /* Remove all entries that are past their TTL */ + for (;;) { + + if (prioq_size(lldp->by_expiry) <= 0) + break; + + p = prioq_peek(lldp->by_expiry); + if (!p) + break; + + if (t <= 0) + t = now(clock_boottime_or_monotonic()); + + if (p->until > t) + break; + + lldp_neighbour_port_remove_and_free(p); + + lldp->statistics.stats_ageouts_total ++; + } +} + +static void lldp_mib_objects_flush(sd_lldp *lldp) { + lldp_neighbour_port *p, *q; + lldp_chassis *c; + + assert(lldp); + assert(lldp->neighbour_mib); + assert(lldp->by_expiry); + + /* Drop all packets */ + while ((c = hashmap_steal_first(lldp->neighbour_mib))) { + + LIST_FOREACH_SAFE(port, p, q, c->ports) { + lldp_neighbour_port_remove_and_free(p); + } + } + + assert(hashmap_size(lldp->neighbour_mib) == 0); + assert(prioq_size(lldp->by_expiry) == 0); +} + +int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + uint8_t *mac, *port_id, type; + lldp_neighbour_port *p; + uint16_t data = 0, length = 0; + char buf[LINE_MAX]; + lldp_chassis *c; + usec_t time; + Iterator i; + int r; + + assert(lldp); + assert(lldp_file); + + r = fopen_temporary(lldp_file, &f, &temp_path); + if (r < 0) + goto fail; + + fchmod(fileno(f), 0644); + + HASHMAP_FOREACH(c, lldp->neighbour_mib, i) { + LIST_FOREACH(port, p, c->ports) { + _cleanup_free_ char *s = NULL; + char *k, *t; + + r = sd_lldp_packet_read_chassis_id(p->packet, &type, &mac, &length); + if (r < 0) + continue; + + sprintf(buf, "'_Chassis=%02x:%02x:%02x:%02x:%02x:%02x' '_CType=%d' ", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type); + + s = strdup(buf); + if (!s) { + r = -ENOMEM; + goto fail; + } + + r = sd_lldp_packet_read_port_id(p->packet, &type, &port_id, &length); + if (r < 0) + continue; + + if (type != LLDP_PORT_SUBTYPE_MAC_ADDRESS) { + k = strndup((char *) port_id, length -1); + if (!k) { + r = -ENOMEM; + goto fail; + } + + sprintf(buf, "'_Port=%s' '_PType=%d' ", k , type); + free(k); + } else { + mac = port_id; + sprintf(buf, "'_Port=%02x:%02x:%02x:%02x:%02x:%02x' '_PType=%d' ", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type); + } + + k = strappend(s, buf); + if (!k) { + r = -ENOMEM; + goto fail; + } + + free(s); + s = k; + + time = now(clock_boottime_or_monotonic()); + + /* Don't write expired packets */ + if (time - p->until <= 0) + continue; + + sprintf(buf, "'_TTL="USEC_FMT"' ", p->until); + + k = strappend(s, buf); + if (!k) { + r = -ENOMEM; + goto fail; + } + + free(s); + s = k; + + r = sd_lldp_packet_read_system_name(p->packet, &k, &length); + if (r < 0) + k = strappend(s, "'_NAME=N/A' "); + else { + t = strndup(k, length); + if (!t) { + r = -ENOMEM; + goto fail; + } + + k = strjoin(s, "'_NAME=", t, "' ", NULL); + free(t); + } + + if (!k) { + r = -ENOMEM; + goto fail; + } + + free(s); + s = k; + + (void) sd_lldp_packet_read_system_capability(p->packet, &data); + + sprintf(buf, "'_CAP=%x'", data); + + k = strappend(s, buf); + if (!k) { + r = -ENOMEM; + goto fail; + } + + free(s); + s = k; + + fprintf(f, "%s\n", s); + } + } + + r = fflush_and_check(f); + if (r < 0) + goto fail; + + if (rename(temp_path, lldp_file) < 0) { + r = -errno; + goto fail; + } + + return 0; + + fail: + if (temp_path) + (void) unlink(temp_path); + + return log_error_errno(r, "Failed to save lldp data %s: %m", lldp_file); +} + +int sd_lldp_start(sd_lldp *lldp) { + int r; + + assert_return(lldp, -EINVAL); + assert_return(lldp->port, -EINVAL); + + lldp->port->status = LLDP_PORT_STATUS_ENABLED; + + lldp_set_state(lldp, LLDP_AGENT_RX_LLDP_INITIALIZE); + + r = lldp_port_start(lldp->port); + if (r < 0) { + log_lldp("Failed to start Port : %s , %s", + lldp->port->ifname, + strerror(-r)); + + lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL); + + return r; + } + + lldp_set_state(lldp, LLDP_AGENT_RX_WAIT_FOR_FRAME); + + return 0; +} + +int sd_lldp_stop(sd_lldp *lldp) { + int r; + + assert_return(lldp, -EINVAL); + assert_return(lldp->port, -EINVAL); + + lldp->port->status = LLDP_PORT_STATUS_DISABLED; + + r = lldp_port_stop(lldp->port); + if (r < 0) + return r; + + lldp_mib_objects_flush(lldp); + + return 0; +} + +int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int priority) { + int r; + + assert_return(lldp, -EINVAL); + assert_return(!lldp->port->event, -EBUSY); + + if (event) + lldp->port->event = sd_event_ref(event); + else { + r = sd_event_default(&lldp->port->event); + if (r < 0) + return r; + } + + lldp->port->event_priority = priority; + + return 0; +} + +int sd_lldp_detach_event(sd_lldp *lldp) { + + assert_return(lldp, -EINVAL); + + lldp->port->event = sd_event_unref(lldp->port->event); + + return 0; +} + +int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata) { + assert_return(lldp, -EINVAL); + + lldp->cb = cb; + lldp->userdata = userdata; + + return 0; +} + +sd_lldp* sd_lldp_unref(sd_lldp *lldp) { + + if (!lldp) + return NULL; + + /* Drop all packets */ + lldp_mib_objects_flush(lldp); + + lldp_port_free(lldp->port); + + hashmap_free(lldp->neighbour_mib); + prioq_free(lldp->by_expiry); + + free(lldp); + return NULL; +} + +int sd_lldp_new(int ifindex, + const char *ifname, + const struct ether_addr *mac, + sd_lldp **ret) { + _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL; + int r; + + assert_return(ret, -EINVAL); + assert_return(ifindex > 0, -EINVAL); + assert_return(ifname, -EINVAL); + assert_return(mac, -EINVAL); + + lldp = new0(sd_lldp, 1); + if (!lldp) + return -ENOMEM; + + r = lldp_port_new(ifindex, ifname, mac, lldp, &lldp->port); + if (r < 0) + return r; + + lldp->neighbour_mib = hashmap_new(&chassis_id_hash_ops); + if (!lldp->neighbour_mib) + return -ENOMEM; + + r = prioq_ensure_allocated(&lldp->by_expiry, + ttl_expiry_item_prioq_compare_func); + if (r < 0) + return r; + + lldp->rx_state = LLDP_AGENT_RX_WAIT_PORT_OPERATIONAL; + + *ret = lldp; + lldp = NULL; + + return 0; +} + +int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs) { + lldp_neighbour_port *p; + lldp_chassis *c; + Iterator iter; + unsigned count = 0, i; + + assert_return(lldp, -EINVAL); + assert_return(tlvs, -EINVAL); + + HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) { + LIST_FOREACH(port, p, c->ports) + count++; + } + + if (!count) { + *tlvs = NULL; + return 0; + } + + *tlvs = new(sd_lldp_packet *, count); + if (!*tlvs) + return -ENOMEM; + + i = 0; + HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) { + LIST_FOREACH(port, p, c->ports) + (*tlvs)[i++] = sd_lldp_packet_ref(p->packet); + } + + return count; +} diff --git a/src/systemd/src/libsystemd/sd-id128/sd-id128.c b/src/systemd/src/libsystemd/sd-id128/sd-id128.c new file mode 100644 index 00000000..bda3b735 --- /dev/null +++ b/src/systemd/src/libsystemd/sd-id128/sd-id128.c @@ -0,0 +1,233 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include + +#include "sd-id128.h" + +#include "fd-util.h" +#include "hexdecoct.h" +#include "io-util.h" +#include "macro.h" +#include "random-util.h" +#include "util.h" + +#if 0 /* NM_IGNORED */ +_public_ char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]) { + unsigned n; + + assert_return(s, NULL); + + for (n = 0; n < 16; n++) { + s[n*2] = hexchar(id.bytes[n] >> 4); + s[n*2+1] = hexchar(id.bytes[n] & 0xF); + } + + s[32] = 0; + + return s; +} + +_public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) { + unsigned n, i; + sd_id128_t t; + bool is_guid = false; + + assert_return(s, -EINVAL); + assert_return(ret, -EINVAL); + + for (n = 0, i = 0; n < 16;) { + int a, b; + + if (s[i] == '-') { + /* Is this a GUID? Then be nice, and skip over + * the dashes */ + + if (i == 8) + is_guid = true; + else if (i == 13 || i == 18 || i == 23) { + if (!is_guid) + return -EINVAL; + } else + return -EINVAL; + + i++; + continue; + } + + a = unhexchar(s[i++]); + if (a < 0) + return -EINVAL; + + b = unhexchar(s[i++]); + if (b < 0) + return -EINVAL; + + t.bytes[n++] = (a << 4) | b; + } + + if (i != (is_guid ? 36 : 32)) + return -EINVAL; + + if (s[i] != 0) + return -EINVAL; + + *ret = t; + return 0; +} + +static sd_id128_t make_v4_uuid(sd_id128_t id) { + /* Stolen from generate_random_uuid() of drivers/char/random.c + * in the kernel sources */ + + /* Set UUID version to 4 --- truly random generation */ + id.bytes[6] = (id.bytes[6] & 0x0F) | 0x40; + + /* Set the UUID variant to DCE */ + id.bytes[8] = (id.bytes[8] & 0x3F) | 0x80; + + return id; +} +#endif + +_public_ int sd_id128_get_machine(sd_id128_t *ret) { + static thread_local sd_id128_t saved_machine_id; + static thread_local bool saved_machine_id_valid = false; + _cleanup_close_ int fd = -1; + char buf[33]; + unsigned j; + sd_id128_t t; + int r; + + assert_return(ret, -EINVAL); + + if (saved_machine_id_valid) { + *ret = saved_machine_id; + return 0; + } + + fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return -errno; + + r = loop_read_exact(fd, buf, 33, false); + if (r < 0) + return r; + if (buf[32] !='\n') + return -EIO; + + for (j = 0; j < 16; j++) { + int a, b; + + a = unhexchar(buf[j*2]); + b = unhexchar(buf[j*2+1]); + + if (a < 0 || b < 0) + return -EIO; + + t.bytes[j] = a << 4 | b; + } + + saved_machine_id = t; + saved_machine_id_valid = true; + + *ret = t; + return 0; +} + +#if 0 /* NM_IGNORED */ +_public_ int sd_id128_get_boot(sd_id128_t *ret) { + static thread_local sd_id128_t saved_boot_id; + static thread_local bool saved_boot_id_valid = false; + _cleanup_close_ int fd = -1; + char buf[36]; + unsigned j; + sd_id128_t t; + char *p; + int r; + + assert_return(ret, -EINVAL); + + if (saved_boot_id_valid) { + *ret = saved_boot_id; + return 0; + } + + fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return -errno; + + r = loop_read_exact(fd, buf, 36, false); + if (r < 0) + return r; + + for (j = 0, p = buf; j < 16; j++) { + int a, b; + + if (p >= buf + 35) + return -EIO; + + if (*p == '-') { + p++; + if (p >= buf + 35) + return -EIO; + } + + a = unhexchar(p[0]); + b = unhexchar(p[1]); + + if (a < 0 || b < 0) + return -EIO; + + t.bytes[j] = a << 4 | b; + + p += 2; + } + + saved_boot_id = t; + saved_boot_id_valid = true; + + *ret = t; + return 0; +} + +_public_ int sd_id128_randomize(sd_id128_t *ret) { + sd_id128_t t; + int r; + + assert_return(ret, -EINVAL); + + r = dev_urandom(&t, sizeof(t)); + if (r < 0) + return r; + + /* Turn this into a valid v4 UUID, to be nice. Note that we + * only guarantee this for newly generated UUIDs, not for + * pre-existing ones. */ + + *ret = make_v4_uuid(t); + return 0; +} +#endif /* NM_IGNORED */ diff --git a/src/systemd/src/shared/dns-domain.c b/src/systemd/src/shared/dns-domain.c new file mode 100644 index 00000000..3a0d9e86 --- /dev/null +++ b/src/systemd/src/shared/dns-domain.c @@ -0,0 +1,1249 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . + ***/ + +#include "nm-sd-adapt.h" + +#ifdef HAVE_LIBIDN +#include +#include +#endif + +#include +#include +#include +#include +#include + +#include "alloc-util.h" +#include "dns-domain.h" +#include "hashmap.h" +#include "hexdecoct.h" +#include "in-addr-util.h" +#include "macro.h" +#include "parse-util.h" +#include "string-util.h" +#include "strv.h" +#include "utf8.h" + +int dns_label_unescape(const char **name, char *dest, size_t sz) { + const char *n; + char *d; + int r = 0; + + assert(name); + assert(*name); + + n = *name; + d = dest; + + for (;;) { + if (*n == '.') { + n++; + break; + } + + if (*n == 0) + break; + + if (r >= DNS_LABEL_MAX) + return -EINVAL; + + if (sz <= 0) + return -ENOBUFS; + + if (*n == '\\') { + /* Escaped character */ + + n++; + + if (*n == 0) + /* Ending NUL */ + return -EINVAL; + + else if (*n == '\\' || *n == '.') { + /* Escaped backslash or dot */ + + if (d) + *(d++) = *n; + sz--; + r++; + n++; + + } else if (n[0] >= '0' && n[0] <= '9') { + unsigned k; + + /* Escaped literal ASCII character */ + + if (!(n[1] >= '0' && n[1] <= '9') || + !(n[2] >= '0' && n[2] <= '9')) + return -EINVAL; + + k = ((unsigned) (n[0] - '0') * 100) + + ((unsigned) (n[1] - '0') * 10) + + ((unsigned) (n[2] - '0')); + + /* Don't allow anything that doesn't + * fit in 8bit. Note that we do allow + * control characters, as some servers + * (e.g. cloudflare) are happy to + * generate labels with them + * inside. */ + if (k > 255) + return -EINVAL; + + if (d) + *(d++) = (char) k; + sz--; + r++; + + n += 3; + } else + return -EINVAL; + + } else if ((uint8_t) *n >= (uint8_t) ' ' && *n != 127) { + + /* Normal character */ + + if (d) + *(d++) = *n; + sz--; + r++; + n++; + } else + return -EINVAL; + } + + /* Empty label that is not at the end? */ + if (r == 0 && *n) + return -EINVAL; + + if (sz >= 1 && d) + *d = 0; + + *name = n; + return r; +} + +/* @label_terminal: terminal character of a label, updated to point to the terminal character of + * the previous label (always skipping one dot) or to NULL if there are no more + * labels. */ +int dns_label_unescape_suffix(const char *name, const char **label_terminal, char *dest, size_t sz) { + const char *terminal; + int r; + + assert(name); + assert(label_terminal); + assert(dest); + + /* no more labels */ + if (!*label_terminal) { + if (sz >= 1) + *dest = 0; + + return 0; + } + + terminal = *label_terminal; + assert(*terminal == '.' || *terminal == 0); + + /* Skip current terminal character (and accept domain names ending it ".") */ + if (*terminal == 0) + terminal--; + if (terminal >= name && *terminal == '.') + terminal--; + + /* Point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */ + for (;;) { + if (terminal < name) { + /* Reached the first label, so indicate that there are no more */ + terminal = NULL; + break; + } + + /* Find the start of the last label */ + if (*terminal == '.') { + const char *y; + unsigned slashes = 0; + + for (y = terminal - 1; y >= name && *y == '\\'; y--) + slashes ++; + + if (slashes % 2 == 0) { + /* The '.' was not escaped */ + name = terminal + 1; + break; + } else { + terminal = y; + continue; + } + } + + terminal --; + } + + r = dns_label_unescape(&name, dest, sz); + if (r < 0) + return r; + + *label_terminal = terminal; + + return r; +} + +int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) { + char *q; + + /* DNS labels must be between 1 and 63 characters long. A + * zero-length label does not exist. See RFC 2182, Section + * 11. */ + + if (l <= 0 || l > DNS_LABEL_MAX) + return -EINVAL; + if (sz < 1) + return -ENOBUFS; + + assert(p); + assert(dest); + + q = dest; + while (l > 0) { + + if (*p == '.' || *p == '\\') { + + /* Dot or backslash */ + + if (sz < 3) + return -ENOBUFS; + + *(q++) = '\\'; + *(q++) = *p; + + sz -= 2; + + } else if (*p == '_' || + *p == '-' || + (*p >= '0' && *p <= '9') || + (*p >= 'a' && *p <= 'z') || + (*p >= 'A' && *p <= 'Z')) { + + /* Proper character */ + + if (sz < 2) + return -ENOBUFS; + + *(q++) = *p; + sz -= 1; + + } else { + + /* Everything else */ + + if (sz < 5) + return -ENOBUFS; + + *(q++) = '\\'; + *(q++) = '0' + (char) ((uint8_t) *p / 100); + *(q++) = '0' + (char) (((uint8_t) *p / 10) % 10); + *(q++) = '0' + (char) ((uint8_t) *p % 10); + + sz -= 4; + + } + + p++; + l--; + } + + *q = 0; + return (int) (q - dest); +} + +int dns_label_escape_new(const char *p, size_t l, char **ret) { + _cleanup_free_ char *s = NULL; + int r; + + assert(p); + assert(ret); + + if (l <= 0 || l > DNS_LABEL_MAX) + return -EINVAL; + + s = new(char, DNS_LABEL_ESCAPED_MAX); + if (!s) + return -ENOMEM; + + r = dns_label_escape(p, l, s, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + return r; + + *ret = s; + s = NULL; + + return r; +} + +int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) { +#ifdef HAVE_LIBIDN + _cleanup_free_ uint32_t *input = NULL; + size_t input_size, l; + const char *p; + bool contains_8bit = false; + char buffer[DNS_LABEL_MAX+1]; + + assert(encoded); + assert(decoded); + + /* Converts an U-label into an A-label */ + + if (encoded_size <= 0) + return -EINVAL; + + for (p = encoded; p < encoded + encoded_size; p++) + if ((uint8_t) *p > 127) + contains_8bit = true; + + if (!contains_8bit) { + if (encoded_size > DNS_LABEL_MAX) + return -EINVAL; + + return 0; + } + + input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); + if (!input) + return -ENOMEM; + + if (idna_to_ascii_4i(input, input_size, buffer, 0) != 0) + return -EINVAL; + + l = strlen(buffer); + + /* Verify that the the result is not longer than one DNS label. */ + if (l <= 0 || l > DNS_LABEL_MAX) + return -EINVAL; + if (l > decoded_max) + return -ENOBUFS; + + memcpy(decoded, buffer, l); + + /* If there's room, append a trailing NUL byte, but only then */ + if (decoded_max > l) + decoded[l] = 0; + + return (int) l; +#else + return 0; +#endif +} + +int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) { +#ifdef HAVE_LIBIDN + size_t input_size, output_size; + _cleanup_free_ uint32_t *input = NULL; + _cleanup_free_ char *result = NULL; + uint32_t *output = NULL; + size_t w; + + /* To be invoked after unescaping. Converts an A-label into an U-label. */ + + assert(encoded); + assert(decoded); + + if (encoded_size <= 0 || encoded_size > DNS_LABEL_MAX) + return -EINVAL; + + if (encoded_size < sizeof(IDNA_ACE_PREFIX)-1) + return 0; + + if (memcmp(encoded, IDNA_ACE_PREFIX, sizeof(IDNA_ACE_PREFIX) -1) != 0) + return 0; + + input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); + if (!input) + return -ENOMEM; + + output_size = input_size; + output = newa(uint32_t, output_size); + + idna_to_unicode_44i(input, input_size, output, &output_size, 0); + + result = stringprep_ucs4_to_utf8(output, output_size, NULL, &w); + if (!result) + return -ENOMEM; + if (w <= 0) + return -EINVAL; + if (w > decoded_max) + return -ENOBUFS; + + memcpy(decoded, result, w); + + /* Append trailing NUL byte if there's space, but only then. */ + if (decoded_max > w) + decoded[w] = 0; + + return w; +#else + return 0; +#endif +} + +int dns_name_concat(const char *a, const char *b, char **_ret) { + _cleanup_free_ char *ret = NULL; + size_t n = 0, allocated = 0; + const char *p = a; + bool first = true; + int r; + + assert(a); + + for (;;) { + char label[DNS_LABEL_MAX]; + int k; + + r = dns_label_unescape(&p, label, sizeof(label)); + if (r < 0) + return r; + if (r == 0) { + if (*p != 0) + return -EINVAL; + + if (b) { + /* Now continue with the second string, if there is one */ + p = b; + b = NULL; + continue; + } + + break; + } + + k = dns_label_undo_idna(label, r, label, sizeof(label)); + if (k < 0) + return k; + if (k > 0) + r = k; + + if (_ret) { + if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) + return -ENOMEM; + + r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + return r; + + if (!first) + ret[n] = '.'; + } else { + char escaped[DNS_LABEL_ESCAPED_MAX]; + + r = dns_label_escape(label, r, escaped, sizeof(escaped)); + if (r < 0) + return r; + } + + if (!first) + n++; + else + first = false; + + n += r; + } + + if (n > DNS_HOSTNAME_MAX) + return -EINVAL; + + if (_ret) { + if (!GREEDY_REALLOC(ret, allocated, n + 1)) + return -ENOMEM; + + ret[n] = 0; + *_ret = ret; + ret = NULL; + } + + return 0; +} + +#if 0 /* NM_IGNORED */ +void dns_name_hash_func(const void *s, struct siphash *state) { + const char *p = s; + int r; + + assert(p); + + while (*p) { + char label[DNS_LABEL_MAX+1]; + int k; + + r = dns_label_unescape(&p, label, sizeof(label)); + if (r < 0) + break; + + k = dns_label_undo_idna(label, r, label, sizeof(label)); + if (k < 0) + break; + if (k > 0) + r = k; + + if (r == 0) + break; + + label[r] = 0; + ascii_strlower(label); + + string_hash_func(label, state); + } + + /* enforce that all names are terminated by the empty label */ + string_hash_func("", state); +} + +int dns_name_compare_func(const void *a, const void *b) { + const char *x, *y; + int r, q, k, w; + + assert(a); + assert(b); + + x = (const char *) a + strlen(a); + y = (const char *) b + strlen(b); + + for (;;) { + char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1]; + + if (x == NULL && y == NULL) + return 0; + + r = dns_label_unescape_suffix(a, &x, la, sizeof(la)); + q = dns_label_unescape_suffix(b, &y, lb, sizeof(lb)); + if (r < 0 || q < 0) + return r - q; + + k = dns_label_undo_idna(la, r, la, sizeof(la)); + w = dns_label_undo_idna(lb, q, lb, sizeof(lb)); + if (k < 0 || w < 0) + return k - w; + if (k > 0) + r = k; + if (w > 0) + q = w; + + la[r] = lb[q] = 0; + r = strcasecmp(la, lb); + if (r != 0) + return r; + } +} + +const struct hash_ops dns_name_hash_ops = { + .hash = dns_name_hash_func, + .compare = dns_name_compare_func +}; + +int dns_name_equal(const char *x, const char *y) { + int r, q, k, w; + + assert(x); + assert(y); + + for (;;) { + char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1]; + + if (*x == 0 && *y == 0) + return true; + + r = dns_label_unescape(&x, la, sizeof(la)); + if (r < 0) + return r; + if (r > 0) { + k = dns_label_undo_idna(la, r, la, sizeof(la)); + if (k < 0) + return k; + if (k > 0) + r = k; + } + + q = dns_label_unescape(&y, lb, sizeof(lb)); + if (q < 0) + return q; + if (q > 0) { + w = dns_label_undo_idna(lb, q, lb, sizeof(lb)); + if (w < 0) + return w; + if (w > 0) + q = w; + } + + /* If one name had fewer labels than the other, this + * will show up as empty label here, which the + * strcasecmp() below will properly consider different + * from a non-empty label. */ + + la[r] = lb[q] = 0; + if (strcasecmp(la, lb) != 0) + return false; + } +} + +int dns_name_endswith(const char *name, const char *suffix) { + const char *n, *s, *saved_n = NULL; + int r, q, k, w; + + assert(name); + assert(suffix); + + n = name; + s = suffix; + + for (;;) { + char ln[DNS_LABEL_MAX+1], ls[DNS_LABEL_MAX+1]; + + r = dns_label_unescape(&n, ln, sizeof(ln)); + if (r < 0) + return r; + if (r > 0) { + k = dns_label_undo_idna(ln, r, ln, sizeof(ln)); + if (k < 0) + return k; + if (k > 0) + r = k; + } + + if (!saved_n) + saved_n = n; + + q = dns_label_unescape(&s, ls, sizeof(ls)); + if (q < 0) + return q; + if (q > 0) { + w = dns_label_undo_idna(ls, q, ls, sizeof(ls)); + if (w < 0) + return w; + if (w > 0) + q = w; + } + + if (r == 0 && q == 0) + return true; + if (r == 0 && saved_n == n) + return false; + + ln[r] = ls[q] = 0; + + if (r != q || strcasecmp(ln, ls)) { + + /* Not the same, let's jump back, and try with the next label again */ + s = suffix; + n = saved_n; + saved_n = NULL; + } + } +} + +int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret) { + const char *n, *s, *saved_before = NULL, *saved_after = NULL, *prefix; + int r, q, k, w; + + assert(name); + assert(old_suffix); + assert(new_suffix); + assert(ret); + + n = name; + s = old_suffix; + + for (;;) { + char ln[DNS_LABEL_MAX+1], ls[DNS_LABEL_MAX+1]; + + if (!saved_before) + saved_before = n; + + r = dns_label_unescape(&n, ln, sizeof(ln)); + if (r < 0) + return r; + if (r > 0) { + k = dns_label_undo_idna(ln, r, ln, sizeof(ln)); + if (k < 0) + return k; + if (k > 0) + r = k; + } + + if (!saved_after) + saved_after = n; + + q = dns_label_unescape(&s, ls, sizeof(ls)); + if (q < 0) + return q; + if (q > 0) { + w = dns_label_undo_idna(ls, q, ls, sizeof(ls)); + if (w < 0) + return w; + if (w > 0) + q = w; + } + + if (r == 0 && q == 0) + break; + if (r == 0 && saved_after == n) { + *ret = NULL; /* doesn't match */ + return 0; + } + + ln[r] = ls[q] = 0; + + if (r != q || strcasecmp(ln, ls)) { + + /* Not the same, let's jump back, and try with the next label again */ + s = old_suffix; + n = saved_after; + saved_after = saved_before = NULL; + } + } + + /* Found it! Now generate the new name */ + prefix = strndupa(name, saved_before - name); + + r = dns_name_concat(prefix, new_suffix, ret); + if (r < 0) + return r; + + return 1; +} + +int dns_name_between(const char *a, const char *b, const char *c) { + int n; + + /* Determine if b is strictly greater than a and strictly smaller than c. + We consider the order of names to be circular, so that if a is + strictly greater than c, we consider b to be between them if it is + either greater than a or smaller than c. This is how the canonical + DNS name order used in NSEC records work. */ + + n = dns_name_compare_func(a, c); + if (n == 0) + return -EINVAL; + else if (n < 0) + /* a<---b--->c */ + return dns_name_compare_func(a, b) < 0 && + dns_name_compare_func(b, c) < 0; + else + /* <--b--c a--b--> */ + return dns_name_compare_func(b, c) < 0 || + dns_name_compare_func(a, b) < 0; +} + +int dns_name_reverse(int family, const union in_addr_union *a, char **ret) { + const uint8_t *p; + int r; + + assert(a); + assert(ret); + + p = (const uint8_t*) a; + + if (family == AF_INET) + r = asprintf(ret, "%u.%u.%u.%u.in-addr.arpa", p[3], p[2], p[1], p[0]); + else if (family == AF_INET6) + r = asprintf(ret, "%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.ip6.arpa", + hexchar(p[15] & 0xF), hexchar(p[15] >> 4), hexchar(p[14] & 0xF), hexchar(p[14] >> 4), + hexchar(p[13] & 0xF), hexchar(p[13] >> 4), hexchar(p[12] & 0xF), hexchar(p[12] >> 4), + hexchar(p[11] & 0xF), hexchar(p[11] >> 4), hexchar(p[10] & 0xF), hexchar(p[10] >> 4), + hexchar(p[ 9] & 0xF), hexchar(p[ 9] >> 4), hexchar(p[ 8] & 0xF), hexchar(p[ 8] >> 4), + hexchar(p[ 7] & 0xF), hexchar(p[ 7] >> 4), hexchar(p[ 6] & 0xF), hexchar(p[ 6] >> 4), + hexchar(p[ 5] & 0xF), hexchar(p[ 5] >> 4), hexchar(p[ 4] & 0xF), hexchar(p[ 4] >> 4), + hexchar(p[ 3] & 0xF), hexchar(p[ 3] >> 4), hexchar(p[ 2] & 0xF), hexchar(p[ 2] >> 4), + hexchar(p[ 1] & 0xF), hexchar(p[ 1] >> 4), hexchar(p[ 0] & 0xF), hexchar(p[ 0] >> 4)); + else + return -EAFNOSUPPORT; + if (r < 0) + return -ENOMEM; + + return 0; +} + +int dns_name_address(const char *p, int *family, union in_addr_union *address) { + int r; + + assert(p); + assert(family); + assert(address); + + r = dns_name_endswith(p, "in-addr.arpa"); + if (r < 0) + return r; + if (r > 0) { + uint8_t a[4]; + unsigned i; + + for (i = 0; i < ELEMENTSOF(a); i++) { + char label[DNS_LABEL_MAX+1]; + + r = dns_label_unescape(&p, label, sizeof(label)); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + if (r > 3) + return -EINVAL; + + r = safe_atou8(label, &a[i]); + if (r < 0) + return r; + } + + r = dns_name_equal(p, "in-addr.arpa"); + if (r <= 0) + return r; + + *family = AF_INET; + address->in.s_addr = htobe32(((uint32_t) a[3] << 24) | + ((uint32_t) a[2] << 16) | + ((uint32_t) a[1] << 8) | + (uint32_t) a[0]); + + return 1; + } + + r = dns_name_endswith(p, "ip6.arpa"); + if (r < 0) + return r; + if (r > 0) { + struct in6_addr a; + unsigned i; + + for (i = 0; i < ELEMENTSOF(a.s6_addr); i++) { + char label[DNS_LABEL_MAX+1]; + int x, y; + + r = dns_label_unescape(&p, label, sizeof(label)); + if (r <= 0) + return r; + if (r != 1) + return -EINVAL; + x = unhexchar(label[0]); + if (x < 0) + return -EINVAL; + + r = dns_label_unescape(&p, label, sizeof(label)); + if (r <= 0) + return r; + if (r != 1) + return -EINVAL; + y = unhexchar(label[0]); + if (y < 0) + return -EINVAL; + + a.s6_addr[ELEMENTSOF(a.s6_addr) - i - 1] = (uint8_t) y << 4 | (uint8_t) x; + } + + r = dns_name_equal(p, "ip6.arpa"); + if (r <= 0) + return r; + + *family = AF_INET6; + address->in6 = a; + return 1; + } + + return 0; +} +#endif /* NM_IGNORED */ + +bool dns_name_is_root(const char *name) { + + assert(name); + + /* There are exactly two ways to encode the root domain name: + * as empty string, or with a single dot. */ + + return STR_IN_SET(name, "", "."); +} + +bool dns_name_is_single_label(const char *name) { + char label[DNS_LABEL_MAX+1]; + int r; + + assert(name); + + r = dns_label_unescape(&name, label, sizeof(label)); + if (r <= 0) + return false; + + return dns_name_is_root(name); +} + +/* Encode a domain name according to RFC 1035 Section 3.1, without compression */ +int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, bool canonical) { + uint8_t *label_length, *out; + int r; + + assert(domain); + assert(buffer); + + out = buffer; + + do { + /* Reserve a byte for label length */ + if (len <= 0) + return -ENOBUFS; + len--; + label_length = out; + out++; + + /* Convert and copy a single label. Note that + * dns_label_unescape() returns 0 when it hits the end + * of the domain name, which we rely on here to encode + * the trailing NUL byte. */ + r = dns_label_unescape(&domain, (char *) out, len); + if (r < 0) + return r; + + if (canonical) { + size_t i; + + /* Optionally, output the name in DNSSEC + * canonical format, as described in RFC 4034, + * section 6.2. Or in other words: in + * lower-case. */ + + for (i = 0; i < (size_t) r; i++) { + if (out[i] >= 'A' && out[i] <= 'Z') + out[i] = out[i] - 'A' + 'a'; + } + } + + /* Fill label length, move forward */ + *label_length = r; + out += r; + len -= r; + + } while (r != 0); + + /* Verify the maximum size of the encoded name. The trailing + * dot + NUL byte account are included this time, hence + * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this + * time. */ + if (out - buffer > DNS_HOSTNAME_MAX + 2) + return -EINVAL; + + return out - buffer; +} + +#if 0 /* NM_IGNORED */ +static bool srv_type_label_is_valid(const char *label, size_t n) { + size_t k; + + assert(label); + + if (n < 2) /* Label needs to be at least 2 chars long */ + return false; + + if (label[0] != '_') /* First label char needs to be underscore */ + return false; + + /* Second char must be a letter */ + if (!(label[1] >= 'A' && label[1] <= 'Z') && + !(label[1] >= 'a' && label[1] <= 'z')) + return false; + + /* Third and further chars must be alphanumeric or a hyphen */ + for (k = 2; k < n; k++) { + if (!(label[k] >= 'A' && label[k] <= 'Z') && + !(label[k] >= 'a' && label[k] <= 'z') && + !(label[k] >= '0' && label[k] <= '9') && + label[k] != '-') + return false; + } + + return true; +} + +bool dns_srv_type_is_valid(const char *name) { + unsigned c = 0; + int r; + + if (!name) + return false; + + for (;;) { + char label[DNS_LABEL_MAX]; + + /* This more or less implements RFC 6335, Section 5.1 */ + + r = dns_label_unescape(&name, label, sizeof(label)); + if (r < 0) + return false; + if (r == 0) + break; + + if (c >= 2) + return false; + + if (!srv_type_label_is_valid(label, r)) + return false; + + c++; + } + + return c == 2; /* exactly two labels */ +} + +bool dns_service_name_is_valid(const char *name) { + size_t l; + + /* This more or less implements RFC 6763, Section 4.1.1 */ + + if (!name) + return false; + + if (!utf8_is_valid(name)) + return false; + + if (string_has_cc(name, NULL)) + return false; + + l = strlen(name); + if (l <= 0) + return false; + if (l > 63) + return false; + + return true; +} + +int dns_service_join(const char *name, const char *type, const char *domain, char **ret) { + char escaped[DNS_LABEL_ESCAPED_MAX]; + _cleanup_free_ char *n = NULL; + int r; + + assert(type); + assert(domain); + assert(ret); + + if (!dns_srv_type_is_valid(type)) + return -EINVAL; + + if (!name) + return dns_name_concat(type, domain, ret); + + if (!dns_service_name_is_valid(name)) + return -EINVAL; + + r = dns_label_escape(name, strlen(name), escaped, sizeof(escaped)); + if (r < 0) + return r; + + r = dns_name_concat(type, domain, &n); + if (r < 0) + return r; + + return dns_name_concat(escaped, n, ret); +} + +static bool dns_service_name_label_is_valid(const char *label, size_t n) { + char *s; + + assert(label); + + if (memchr(label, 0, n)) + return false; + + s = strndupa(label, n); + return dns_service_name_is_valid(s); +} + +int dns_service_split(const char *joined, char **_name, char **_type, char **_domain) { + _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL; + const char *p = joined, *q = NULL, *d = NULL; + char a[DNS_LABEL_MAX], b[DNS_LABEL_MAX], c[DNS_LABEL_MAX]; + int an, bn, cn, r; + unsigned x = 0; + + assert(joined); + + /* Get first label from the full name */ + an = dns_label_unescape(&p, a, sizeof(a)); + if (an < 0) + return an; + + if (an > 0) { + x++; + + /* If there was a first label, try to get the second one */ + bn = dns_label_unescape(&p, b, sizeof(b)); + if (bn < 0) + return bn; + + if (bn > 0) { + x++; + + /* If there was a second label, try to get the third one */ + q = p; + cn = dns_label_unescape(&p, c, sizeof(c)); + if (cn < 0) + return cn; + + if (cn > 0) + x++; + } else + cn = 0; + } else + an = 0; + + if (x >= 2 && srv_type_label_is_valid(b, bn)) { + + if (x >= 3 && srv_type_label_is_valid(c, cn)) { + + if (dns_service_name_label_is_valid(a, an)) { + + /* OK, got . . . */ + + name = strndup(a, an); + if (!name) + return -ENOMEM; + + type = new(char, bn+1+cn+1); + if (!type) + return -ENOMEM; + strcpy(stpcpy(stpcpy(type, b), "."), c); + + d = p; + goto finish; + } + + } else if (srv_type_label_is_valid(a, an)) { + + /* OK, got . . */ + + name = NULL; + + type = new(char, an+1+bn+1); + if (!type) + return -ENOMEM; + strcpy(stpcpy(stpcpy(type, a), "."), b); + + d = q; + goto finish; + } + } + + name = NULL; + type = NULL; + d = joined; + +finish: + r = dns_name_normalize(d, &domain); + if (r < 0) + return r; + + if (_domain) { + *_domain = domain; + domain = NULL; + } + + if (_type) { + *_type = type; + type = NULL; + } + + if (_name) { + *_name = name; + name = NULL; + } + + return 0; +} + +int dns_name_suffix(const char *name, unsigned n_labels, const char **ret) { + const char* labels[DNS_N_LABELS_MAX+1]; + unsigned n = 0; + const char *p; + int r; + + assert(name); + assert(ret); + + p = name; + for (;;) { + if (n > DNS_N_LABELS_MAX) + return -EINVAL; + + labels[n] = p; + + r = dns_name_parent(&p); + if (r < 0) + return r; + if (r == 0) + break; + + n++; + } + + if (n < n_labels) + return -EINVAL; + + *ret = labels[n - n_labels]; + return (int) (n - n_labels); +} + +int dns_name_count_labels(const char *name) { + unsigned n = 0; + const char *p; + int r; + + assert(name); + + p = name; + for (;;) { + r = dns_name_parent(&p); + if (r < 0) + return r; + if (r == 0) + break; + + if (n >= DNS_N_LABELS_MAX) + return -EINVAL; + + n++; + } + + return (int) n; +} + +int dns_name_equal_skip(const char *a, unsigned n_labels, const char *b) { + int r; + + assert(a); + assert(b); + + while (n_labels > 0) { + + r = dns_name_parent(&a); + if (r <= 0) + return r; + + n_labels --; + } + + return dns_name_equal(a, b); +} +#endif /* NM_IGNORED */ diff --git a/src/systemd/src/shared/dns-domain.h b/src/systemd/src/shared/dns-domain.h new file mode 100644 index 00000000..54860fb8 --- /dev/null +++ b/src/systemd/src/shared/dns-domain.h @@ -0,0 +1,107 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . + ***/ + +#pragma once + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "hashmap.h" +#include "in-addr-util.h" + +/* Length of a single label, with all escaping removed, excluding any trailing dot or NUL byte */ +#define DNS_LABEL_MAX 63 + +/* Worst case length of a single label, with all escaping applied and room for a trailing NUL byte. */ +#define DNS_LABEL_ESCAPED_MAX (DNS_LABEL_MAX*4+1) + +/* Maximum length of a full hostname, consisting of a series of unescaped labels, and no trailing dot or NUL byte */ +#define DNS_HOSTNAME_MAX 253 + +/* Maximum length of a full hostname, on the wire, including the final NUL byte */ +#define DNS_WIRE_FOMAT_HOSTNAME_MAX 255 + +/* Maximum number of labels per valid hostname */ +#define DNS_N_LABELS_MAX 127 + +int dns_label_unescape(const char **name, char *dest, size_t sz); +int dns_label_unescape_suffix(const char *name, const char **label_end, char *dest, size_t sz); +int dns_label_escape(const char *p, size_t l, char *dest, size_t sz); +int dns_label_escape_new(const char *p, size_t l, char **ret); + +static inline int dns_name_parent(const char **name) { + return dns_label_unescape(name, NULL, DNS_LABEL_MAX); +} + +int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max); +int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max); + +int dns_name_concat(const char *a, const char *b, char **ret); + +static inline int dns_name_normalize(const char *s, char **ret) { + /* dns_name_concat() normalizes as a side-effect */ + return dns_name_concat(s, NULL, ret); +} + +static inline int dns_name_is_valid(const char *s) { + int r; + + /* dns_name_normalize() verifies as a side effect */ + r = dns_name_normalize(s, NULL); + if (r == -EINVAL) + return 0; + if (r < 0) + return r; + return 1; +} + +void dns_name_hash_func(const void *s, struct siphash *state); +int dns_name_compare_func(const void *a, const void *b); +extern const struct hash_ops dns_name_hash_ops; + +int dns_name_between(const char *a, const char *b, const char *c); +int dns_name_equal(const char *x, const char *y); +int dns_name_endswith(const char *name, const char *suffix); + +int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret); + +int dns_name_reverse(int family, const union in_addr_union *a, char **ret); +int dns_name_address(const char *p, int *family, union in_addr_union *a); + +bool dns_name_is_root(const char *name); +bool dns_name_is_single_label(const char *name); + +int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, bool canonical); + +bool dns_srv_type_is_valid(const char *name); +bool dns_service_name_is_valid(const char *name); + +int dns_service_join(const char *name, const char *type, const char *domain, char **ret); +int dns_service_split(const char *joined, char **name, char **type, char **domain); + +int dns_name_suffix(const char *name, unsigned n_labels, const char **ret); +int dns_name_count_labels(const char *name); + +int dns_name_equal_skip(const char *a, unsigned n_labels, const char *b); diff --git a/src/systemd/src/systemd/_sd-common.h b/src/systemd/src/systemd/_sd-common.h new file mode 100644 index 00000000..5960a1c3 --- /dev/null +++ b/src/systemd/src/systemd/_sd-common.h @@ -0,0 +1,87 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdcommonhfoo +#define foosdcommonhfoo + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +/* This is a private header; never even think of including this directly! */ + +#if __INCLUDE_LEVEL__ <= 1 +#error "Do not include _sd-common.h directly; it is a private header." +#endif + +#ifndef _sd_printf_ +# if __GNUC__ >= 4 +# define _sd_printf_(a,b) __attribute__ ((format (printf, a, b))) +# else +# define _sd_printf_(a,b) +# endif +#endif + +#ifndef _sd_sentinel_ +# define _sd_sentinel_ __attribute__((sentinel)) +#endif + +#ifndef _sd_packed_ +# define _sd_packed_ __attribute__((packed)) +#endif + +#ifndef _sd_pure_ +# define _sd_pure_ __attribute__((pure)) +#endif + +#ifndef _SD_STRINGIFY +# define _SD_XSTRINGIFY(x) #x +# define _SD_STRINGIFY(x) _SD_XSTRINGIFY(x) +#endif + +#ifndef _SD_BEGIN_DECLARATIONS +# ifdef __cplusplus +# define _SD_BEGIN_DECLARATIONS \ + extern "C" { \ + struct _sd_useless_struct_to_allow_trailing_semicolon_ +# else +# define _SD_BEGIN_DECLARATIONS \ + struct _sd_useless_struct_to_allow_trailing_semicolon_ +# endif +#endif + +#ifndef _SD_END_DECLARATIONS +# ifdef __cplusplus +# define _SD_END_DECLARATIONS \ + } \ + struct _sd_useless_cpp_struct_to_allow_trailing_semicolon_ +# else +# define _SD_END_DECLARATIONS \ + struct _sd_useless_struct_to_allow_trailing_semicolon_ +# endif +#endif + +#define _SD_DEFINE_POINTER_CLEANUP_FUNC(type, func) \ + static inline void func##p(type **p) { \ + if (*p) \ + func(*p); \ + } \ + struct _sd_useless_struct_to_allow_trailing_semicolon_ + +#endif diff --git a/src/systemd/src/systemd/sd-dhcp-client.h b/src/systemd/src/systemd/sd-dhcp-client.h new file mode 100644 index 00000000..0fad8f36 --- /dev/null +++ b/src/systemd/src/systemd/sd-dhcp-client.h @@ -0,0 +1,86 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosddhcpclienthfoo +#define foosddhcpclienthfoo + +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "sd-dhcp-lease.h" +#include "sd-event.h" + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +enum { + SD_DHCP_CLIENT_EVENT_STOP = 0, + SD_DHCP_CLIENT_EVENT_IP_ACQUIRE = 1, + SD_DHCP_CLIENT_EVENT_IP_CHANGE = 2, + SD_DHCP_CLIENT_EVENT_EXPIRED = 3, + SD_DHCP_CLIENT_EVENT_RENEW = 4, +}; + +typedef struct sd_dhcp_client sd_dhcp_client; + +typedef void (*sd_dhcp_client_cb_t)(sd_dhcp_client *client, int event, + void *userdata); +int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb, + void *userdata); + +int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option); +int sd_dhcp_client_set_request_address(sd_dhcp_client *client, + const struct in_addr *last_address); +int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast); +int sd_dhcp_client_set_index(sd_dhcp_client *client, int interface_index); +int sd_dhcp_client_set_mac(sd_dhcp_client *client, const uint8_t *addr, + size_t addr_len, uint16_t arp_type); +int sd_dhcp_client_set_client_id(sd_dhcp_client *client, uint8_t type, + const uint8_t *data, size_t data_len); +int sd_dhcp_client_get_client_id(sd_dhcp_client *client, uint8_t *type, + const uint8_t **data, size_t *data_len); +int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu); +int sd_dhcp_client_set_hostname(sd_dhcp_client *client, const char *hostname); +int sd_dhcp_client_set_vendor_class_identifier(sd_dhcp_client *client, const char *vci); +int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret); + +int sd_dhcp_client_stop(sd_dhcp_client *client); +int sd_dhcp_client_start(sd_dhcp_client *client); + +sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client); +sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client); + +int sd_dhcp_client_new(sd_dhcp_client **ret); + +int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int priority); +int sd_dhcp_client_detach_event(sd_dhcp_client *client); +sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client); + +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_client, sd_dhcp_client_unref); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/src/systemd/sd-dhcp-lease.h b/src/systemd/src/systemd/sd-dhcp-lease.h new file mode 100644 index 00000000..eed38eeb --- /dev/null +++ b/src/systemd/src/systemd/sd-dhcp-lease.h @@ -0,0 +1,67 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosddhcpleasehfoo +#define foosddhcpleasehfoo + +/*** + This file is part of systemd. + + Copyright (C) 2013 Intel Corporation. All rights reserved. + Copyright (C) 2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +typedef struct sd_dhcp_lease sd_dhcp_lease; +struct sd_dhcp_route; + +sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease); +sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease); + +int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr); +int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime); +int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1); +int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2); +int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr); +int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr); +int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr); +int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr); +int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr); +int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr); +int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr); +int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu); +int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname); +int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname); +int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path); +int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes); +int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len); +int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len); +int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone); + +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_lease, sd_dhcp_lease_unref); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/src/systemd/sd-dhcp6-client.h b/src/systemd/src/systemd/sd-dhcp6-client.h new file mode 100644 index 00000000..c18d91bf --- /dev/null +++ b/src/systemd/src/systemd/sd-dhcp6-client.h @@ -0,0 +1,81 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosddhcp6clienthfoo +#define foosddhcp6clienthfoo + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include + +#include "sd-dhcp6-lease.h" +#include "sd-event.h" + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +enum { + SD_DHCP6_CLIENT_EVENT_STOP = 0, + SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE = 10, + SD_DHCP6_CLIENT_EVENT_RETRANS_MAX = 11, + SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE = 12, + SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13, +}; + +typedef struct sd_dhcp6_client sd_dhcp6_client; + +typedef void (*sd_dhcp6_client_cb_t)(sd_dhcp6_client *client, int event, + void *userdata); +int sd_dhcp6_client_set_callback(sd_dhcp6_client *client, + sd_dhcp6_client_cb_t cb, void *userdata); + +int sd_dhcp6_client_set_index(sd_dhcp6_client *client, int interface_index); +int sd_dhcp6_client_set_local_address(sd_dhcp6_client *client, const struct in6_addr *local_address); +int sd_dhcp6_client_set_mac(sd_dhcp6_client *client, const uint8_t *addr, + size_t addr_len, uint16_t arp_type); +int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, uint16_t type, uint8_t *duid, + size_t duid_len); +int sd_dhcp6_client_set_information_request(sd_dhcp6_client *client, int enabled); +int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enabled); +int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, + uint16_t option); + +int sd_dhcp6_client_get_lease(sd_dhcp6_client *client, sd_dhcp6_lease **ret); + +int sd_dhcp6_client_stop(sd_dhcp6_client *client); +int sd_dhcp6_client_start(sd_dhcp6_client *client); +int sd_dhcp6_client_is_running(sd_dhcp6_client *client); +int sd_dhcp6_client_attach_event(sd_dhcp6_client *client, sd_event *event, + int priority); +int sd_dhcp6_client_detach_event(sd_dhcp6_client *client); +sd_event *sd_dhcp6_client_get_event(sd_dhcp6_client *client); +sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client); +sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client); +int sd_dhcp6_client_new(sd_dhcp6_client **ret); + +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp6_client, sd_dhcp6_client_unref); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/src/systemd/sd-dhcp6-lease.h b/src/systemd/src/systemd/sd-dhcp6-lease.h new file mode 100644 index 00000000..149cb239 --- /dev/null +++ b/src/systemd/src/systemd/sd-dhcp6-lease.h @@ -0,0 +1,56 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosddhcp6leasehfoo +#define foosddhcp6leasehfoo + +/*** + This file is part of systemd. + + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014-2015 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +typedef struct sd_dhcp6_lease sd_dhcp6_lease; + +void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease); +int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, + struct in6_addr *addr, + uint32_t *lifetime_preferred, + uint32_t *lifetime_valid); + +int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, struct in6_addr **addrs); +int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***domains); +int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, + struct in6_addr **addrs); +int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn); + +sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease); +sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease); + +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp6_lease, sd_dhcp6_lease_unref); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/src/systemd/sd-event.h b/src/systemd/src/systemd/sd-event.h new file mode 100644 index 00000000..17b95244 --- /dev/null +++ b/src/systemd/src/systemd/sd-event.h @@ -0,0 +1,142 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdeventhfoo +#define foosdeventhfoo + +/*** + This file is part of systemd. + + Copyright 2013 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include +#include +#include +#include + +#include "_sd-common.h" + +/* + Why is this better than pure epoll? + + - Supports event source prioritization + - Scales better with a large number of time events because it does not require one timerfd each + - Automatically tries to coalesce timer events system-wide + - Handles signals and child PIDs +*/ + +_SD_BEGIN_DECLARATIONS; + +typedef struct sd_event sd_event; +typedef struct sd_event_source sd_event_source; + +enum { + SD_EVENT_OFF = 0, + SD_EVENT_ON = 1, + SD_EVENT_ONESHOT = -1 +}; + +enum { + SD_EVENT_INITIAL, + SD_EVENT_ARMED, + SD_EVENT_PENDING, + SD_EVENT_RUNNING, + SD_EVENT_EXITING, + SD_EVENT_FINISHED, + SD_EVENT_PREPARING, +}; + +enum { + /* And everything in-between and outside is good too */ + SD_EVENT_PRIORITY_IMPORTANT = -100, + SD_EVENT_PRIORITY_NORMAL = 0, + SD_EVENT_PRIORITY_IDLE = 100 +}; + +typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata); +typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata); +typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata); +typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata); +typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata); + +int sd_event_default(sd_event **e); + +int sd_event_new(sd_event **e); +sd_event* sd_event_ref(sd_event *e); +sd_event* sd_event_unref(sd_event *e); + +int sd_event_add_io(sd_event *e, sd_event_source **s, int fd, uint32_t events, sd_event_io_handler_t callback, void *userdata); +int sd_event_add_time(sd_event *e, sd_event_source **s, clockid_t clock, uint64_t usec, uint64_t accuracy, sd_event_time_handler_t callback, void *userdata); +int sd_event_add_signal(sd_event *e, sd_event_source **s, int sig, sd_event_signal_handler_t callback, void *userdata); +int sd_event_add_child(sd_event *e, sd_event_source **s, pid_t pid, int options, sd_event_child_handler_t callback, void *userdata); +int sd_event_add_defer(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); +int sd_event_add_post(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); +int sd_event_add_exit(sd_event *e, sd_event_source **s, sd_event_handler_t callback, void *userdata); + +int sd_event_prepare(sd_event *e); +int sd_event_wait(sd_event *e, uint64_t usec); +int sd_event_dispatch(sd_event *e); +int sd_event_run(sd_event *e, uint64_t usec); +int sd_event_loop(sd_event *e); +int sd_event_exit(sd_event *e, int code); + +int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec); + +int sd_event_get_fd(sd_event *e); +int sd_event_get_state(sd_event *e); +int sd_event_get_tid(sd_event *e, pid_t *tid); +int sd_event_get_exit_code(sd_event *e, int *code); +int sd_event_set_watchdog(sd_event *e, int b); +int sd_event_get_watchdog(sd_event *e); + +sd_event_source* sd_event_source_ref(sd_event_source *s); +sd_event_source* sd_event_source_unref(sd_event_source *s); + +sd_event *sd_event_source_get_event(sd_event_source *s); +void* sd_event_source_get_userdata(sd_event_source *s); +void* sd_event_source_set_userdata(sd_event_source *s, void *userdata); + +int sd_event_source_set_description(sd_event_source *s, const char *description); +int sd_event_source_get_description(sd_event_source *s, const char **description); +int sd_event_source_set_prepare(sd_event_source *s, sd_event_handler_t callback); +int sd_event_source_get_pending(sd_event_source *s); +int sd_event_source_get_priority(sd_event_source *s, int64_t *priority); +int sd_event_source_set_priority(sd_event_source *s, int64_t priority); +int sd_event_source_get_enabled(sd_event_source *s, int *enabled); +int sd_event_source_set_enabled(sd_event_source *s, int enabled); +int sd_event_source_get_io_fd(sd_event_source *s); +int sd_event_source_set_io_fd(sd_event_source *s, int fd); +int sd_event_source_get_io_events(sd_event_source *s, uint32_t* events); +int sd_event_source_set_io_events(sd_event_source *s, uint32_t events); +int sd_event_source_get_io_revents(sd_event_source *s, uint32_t* revents); +int sd_event_source_get_time(sd_event_source *s, uint64_t *usec); +int sd_event_source_set_time(sd_event_source *s, uint64_t usec); +int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec); +int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec); +int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock); +int sd_event_source_get_signal(sd_event_source *s); +int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid); + +/* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */ +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event_source, sd_event_source_unref); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/src/systemd/sd-id128.h b/src/systemd/src/systemd/sd-id128.h new file mode 100644 index 00000000..da1bb2fa --- /dev/null +++ b/src/systemd/src/systemd/sd-id128.h @@ -0,0 +1,119 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdid128hfoo +#define foosdid128hfoo + +/*** + This file is part of systemd. + + Copyright 2011 Lennart Poettering + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +/* 128-bit ID APIs. See sd-id128(3) for more information. */ + +typedef union sd_id128 sd_id128_t; + +union sd_id128 { + uint8_t bytes[16]; + uint64_t qwords[2]; +}; + +#define SD_ID128_STRING_MAX 33 + +char *sd_id128_to_string(sd_id128_t id, char s[SD_ID128_STRING_MAX]); + +int sd_id128_from_string(const char *s, sd_id128_t *ret); + +int sd_id128_randomize(sd_id128_t *ret); + +int sd_id128_get_machine(sd_id128_t *ret); + +int sd_id128_get_boot(sd_id128_t *ret); + +#define SD_ID128_MAKE(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \ + ((const sd_id128_t) { .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \ + 0x##v8, 0x##v9, 0x##v10, 0x##v11, 0x##v12, 0x##v13, 0x##v14, 0x##v15 }}) + +#define SD_ID128_ARRAY(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15) \ + { .bytes = { 0x##v0, 0x##v1, 0x##v2, 0x##v3, 0x##v4, 0x##v5, 0x##v6, 0x##v7, \ + 0x##v8, 0x##v9, 0x##v10, 0x##v11, 0x##v12, 0x##v13, 0x##v14, 0x##v15 }} + +/* Note that SD_ID128_FORMAT_VAL will evaluate the passed argument 16 + * times. It is hence not a good idea to call this macro with an + * expensive function as parameter or an expression with side + * effects */ + +#define SD_ID128_FORMAT_STR "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x" +#define SD_ID128_FORMAT_VAL(x) (x).bytes[0], (x).bytes[1], (x).bytes[2], (x).bytes[3], (x).bytes[4], (x).bytes[5], (x).bytes[6], (x).bytes[7], (x).bytes[8], (x).bytes[9], (x).bytes[10], (x).bytes[11], (x).bytes[12], (x).bytes[13], (x).bytes[14], (x).bytes[15] + +#define SD_ID128_CONST_STR(x) \ + ((const char[SD_ID128_STRING_MAX]) { \ + ((x).bytes[0] >> 4) >= 10 ? 'a' + ((x).bytes[0] >> 4) - 10 : '0' + ((x).bytes[0] >> 4), \ + ((x).bytes[0] & 15) >= 10 ? 'a' + ((x).bytes[0] & 15) - 10 : '0' + ((x).bytes[0] & 15), \ + ((x).bytes[1] >> 4) >= 10 ? 'a' + ((x).bytes[1] >> 4) - 10 : '0' + ((x).bytes[1] >> 4), \ + ((x).bytes[1] & 15) >= 10 ? 'a' + ((x).bytes[1] & 15) - 10 : '0' + ((x).bytes[1] & 15), \ + ((x).bytes[2] >> 4) >= 10 ? 'a' + ((x).bytes[2] >> 4) - 10 : '0' + ((x).bytes[2] >> 4), \ + ((x).bytes[2] & 15) >= 10 ? 'a' + ((x).bytes[2] & 15) - 10 : '0' + ((x).bytes[2] & 15), \ + ((x).bytes[3] >> 4) >= 10 ? 'a' + ((x).bytes[3] >> 4) - 10 : '0' + ((x).bytes[3] >> 4), \ + ((x).bytes[3] & 15) >= 10 ? 'a' + ((x).bytes[3] & 15) - 10 : '0' + ((x).bytes[3] & 15), \ + ((x).bytes[4] >> 4) >= 10 ? 'a' + ((x).bytes[4] >> 4) - 10 : '0' + ((x).bytes[4] >> 4), \ + ((x).bytes[4] & 15) >= 10 ? 'a' + ((x).bytes[4] & 15) - 10 : '0' + ((x).bytes[4] & 15), \ + ((x).bytes[5] >> 4) >= 10 ? 'a' + ((x).bytes[5] >> 4) - 10 : '0' + ((x).bytes[5] >> 4), \ + ((x).bytes[5] & 15) >= 10 ? 'a' + ((x).bytes[5] & 15) - 10 : '0' + ((x).bytes[5] & 15), \ + ((x).bytes[6] >> 4) >= 10 ? 'a' + ((x).bytes[6] >> 4) - 10 : '0' + ((x).bytes[6] >> 4), \ + ((x).bytes[6] & 15) >= 10 ? 'a' + ((x).bytes[6] & 15) - 10 : '0' + ((x).bytes[6] & 15), \ + ((x).bytes[7] >> 4) >= 10 ? 'a' + ((x).bytes[7] >> 4) - 10 : '0' + ((x).bytes[7] >> 4), \ + ((x).bytes[7] & 15) >= 10 ? 'a' + ((x).bytes[7] & 15) - 10 : '0' + ((x).bytes[7] & 15), \ + ((x).bytes[8] >> 4) >= 10 ? 'a' + ((x).bytes[8] >> 4) - 10 : '0' + ((x).bytes[8] >> 4), \ + ((x).bytes[8] & 15) >= 10 ? 'a' + ((x).bytes[8] & 15) - 10 : '0' + ((x).bytes[8] & 15), \ + ((x).bytes[9] >> 4) >= 10 ? 'a' + ((x).bytes[9] >> 4) - 10 : '0' + ((x).bytes[9] >> 4), \ + ((x).bytes[9] & 15) >= 10 ? 'a' + ((x).bytes[9] & 15) - 10 : '0' + ((x).bytes[9] & 15), \ + ((x).bytes[10] >> 4) >= 10 ? 'a' + ((x).bytes[10] >> 4) - 10 : '0' + ((x).bytes[10] >> 4), \ + ((x).bytes[10] & 15) >= 10 ? 'a' + ((x).bytes[10] & 15) - 10 : '0' + ((x).bytes[10] & 15), \ + ((x).bytes[11] >> 4) >= 10 ? 'a' + ((x).bytes[11] >> 4) - 10 : '0' + ((x).bytes[11] >> 4), \ + ((x).bytes[11] & 15) >= 10 ? 'a' + ((x).bytes[11] & 15) - 10 : '0' + ((x).bytes[11] & 15), \ + ((x).bytes[12] >> 4) >= 10 ? 'a' + ((x).bytes[12] >> 4) - 10 : '0' + ((x).bytes[12] >> 4), \ + ((x).bytes[12] & 15) >= 10 ? 'a' + ((x).bytes[12] & 15) - 10 : '0' + ((x).bytes[12] & 15), \ + ((x).bytes[13] >> 4) >= 10 ? 'a' + ((x).bytes[13] >> 4) - 10 : '0' + ((x).bytes[13] >> 4), \ + ((x).bytes[13] & 15) >= 10 ? 'a' + ((x).bytes[13] & 15) - 10 : '0' + ((x).bytes[13] & 15), \ + ((x).bytes[14] >> 4) >= 10 ? 'a' + ((x).bytes[14] >> 4) - 10 : '0' + ((x).bytes[14] >> 4), \ + ((x).bytes[14] & 15) >= 10 ? 'a' + ((x).bytes[14] & 15) - 10 : '0' + ((x).bytes[14] & 15), \ + ((x).bytes[15] >> 4) >= 10 ? 'a' + ((x).bytes[15] >> 4) - 10 : '0' + ((x).bytes[15] >> 4), \ + ((x).bytes[15] & 15) >= 10 ? 'a' + ((x).bytes[15] & 15) - 10 : '0' + ((x).bytes[15] & 15), \ + 0 }) + +_sd_pure_ static inline int sd_id128_equal(sd_id128_t a, sd_id128_t b) { + return memcmp(&a, &b, 16) == 0; +} + +_sd_pure_ static inline int sd_id128_is_null(sd_id128_t a) { + return a.qwords[0] == 0 && a.qwords[1] == 0; +} + +#define SD_ID128_NULL ((const sd_id128_t) { .qwords = { 0, 0 }}) + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/src/systemd/sd-ipv4acd.h b/src/systemd/src/systemd/sd-ipv4acd.h new file mode 100644 index 00000000..14d0e5a9 --- /dev/null +++ b/src/systemd/src/systemd/sd-ipv4acd.h @@ -0,0 +1,64 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdipv4acdfoo +#define foosdipv4acdfoo + +/*** + This file is part of systemd. + + Copyright (C) 2014 Axis Communications AB. All rights reserved. + Copyright (C) 2015 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +#include "sd-event.h" + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +enum { + SD_IPV4ACD_EVENT_STOP = 0, + SD_IPV4ACD_EVENT_BIND = 1, + SD_IPV4ACD_EVENT_CONFLICT = 2, +}; + +typedef struct sd_ipv4acd sd_ipv4acd; +typedef void (*sd_ipv4acd_cb_t)(sd_ipv4acd *ll, int event, void *userdata); + +int sd_ipv4acd_detach_event(sd_ipv4acd *ll); +int sd_ipv4acd_attach_event(sd_ipv4acd *ll, sd_event *event, int priority); +int sd_ipv4acd_get_address(sd_ipv4acd *ll, struct in_addr *address); +int sd_ipv4acd_set_callback(sd_ipv4acd *ll, sd_ipv4acd_cb_t cb, void *userdata); +int sd_ipv4acd_set_mac(sd_ipv4acd *ll, const struct ether_addr *addr); +int sd_ipv4acd_set_index(sd_ipv4acd *ll, int interface_index); +int sd_ipv4acd_set_address(sd_ipv4acd *ll, const struct in_addr *address); +int sd_ipv4acd_is_running(sd_ipv4acd *ll); +int sd_ipv4acd_start(sd_ipv4acd *ll); +int sd_ipv4acd_stop(sd_ipv4acd *ll); +sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll); +sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll); +int sd_ipv4acd_new(sd_ipv4acd **ret); + +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ipv4acd, sd_ipv4acd_unref); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/src/systemd/sd-ipv4ll.h b/src/systemd/src/systemd/sd-ipv4ll.h new file mode 100644 index 00000000..307aa6f7 --- /dev/null +++ b/src/systemd/src/systemd/sd-ipv4ll.h @@ -0,0 +1,64 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdipv4llfoo +#define foosdipv4llfoo + +/*** + This file is part of systemd. + + Copyright (C) 2014 Axis Communications AB. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +#include "sd-event.h" + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +enum { + SD_IPV4LL_EVENT_STOP = 0, + SD_IPV4LL_EVENT_BIND = 1, + SD_IPV4LL_EVENT_CONFLICT = 2, +}; + +typedef struct sd_ipv4ll sd_ipv4ll; +typedef void (*sd_ipv4ll_cb_t)(sd_ipv4ll *ll, int event, void *userdata); + +int sd_ipv4ll_detach_event(sd_ipv4ll *ll); +int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int priority); +int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address); +int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_cb_t cb, void *userdata); +int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr); +int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index); +int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address); +int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, unsigned seed); +int sd_ipv4ll_is_running(sd_ipv4ll *ll); +int sd_ipv4ll_start(sd_ipv4ll *ll); +int sd_ipv4ll_stop(sd_ipv4ll *ll); +sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll); +sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll); +int sd_ipv4ll_new (sd_ipv4ll **ret); + +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ipv4ll, sd_ipv4ll_unref); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/src/systemd/sd-lldp.h b/src/systemd/src/systemd/sd-lldp.h new file mode 100644 index 00000000..d4e7a4fa --- /dev/null +++ b/src/systemd/src/systemd/sd-lldp.h @@ -0,0 +1,91 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdlldphfoo +#define foosdlldphfoo + +/*** + This file is part of systemd. + + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014 Susant Sahani + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +#include "sd-event.h" + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +enum { + SD_LLDP_EVENT_UPDATE_INFO = 0, +}; + +enum { + SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE, + SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE, + SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE, +}; + +typedef struct sd_lldp sd_lldp; +typedef struct sd_lldp_packet sd_lldp_packet; + +typedef void (*sd_lldp_cb_t)(sd_lldp *lldp, int event, void *userdata); + +int sd_lldp_new(int ifindex, const char *ifname, const struct ether_addr *mac, sd_lldp **ret); +sd_lldp* sd_lldp_unref(sd_lldp *lldp); + +int sd_lldp_start(sd_lldp *lldp); +int sd_lldp_stop(sd_lldp *lldp); + +int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int priority); +int sd_lldp_detach_event(sd_lldp *lldp); + +int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata); +int sd_lldp_save(sd_lldp *lldp, const char *file); + +int sd_lldp_packet_read_chassis_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length); +int sd_lldp_packet_read_port_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length); +int sd_lldp_packet_read_ttl(sd_lldp_packet *tlv, uint16_t *ttl); +int sd_lldp_packet_read_system_name(sd_lldp_packet *tlv, char **data, uint16_t *length); +int sd_lldp_packet_read_system_description(sd_lldp_packet *tlv, char **data, uint16_t *length); +int sd_lldp_packet_read_system_capability(sd_lldp_packet *tlv, uint16_t *data); +int sd_lldp_packet_read_port_description(sd_lldp_packet *tlv, char **data, uint16_t *length); + +/* IEEE 802.1 organizationally specific TLVs */ +int sd_lldp_packet_read_port_vlan_id(sd_lldp_packet *tlv, uint16_t *id); +int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id); +int sd_lldp_packet_read_vlan_name(sd_lldp_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length); +int sd_lldp_packet_read_management_vid(sd_lldp_packet *tlv, uint16_t *id); +int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id); + +sd_lldp_packet *sd_lldp_packet_ref(sd_lldp_packet *tlv); +sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv); + +int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest); + +int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs); + +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp, sd_lldp_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_packet, sd_lldp_packet_unref); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/systemd/src/systemd/sd-ndisc.h b/src/systemd/src/systemd/sd-ndisc.h new file mode 100644 index 00000000..cc674336 --- /dev/null +++ b/src/systemd/src/systemd/sd-ndisc.h @@ -0,0 +1,88 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foosdndiscfoo +#define foosdndiscfoo + +/*** + This file is part of systemd. + + Copyright (C) 2014 Intel Corporation. All rights reserved. + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "nm-sd-adapt.h" + +#include +#include + +#include "sd-event.h" + +#include "_sd-common.h" + +_SD_BEGIN_DECLARATIONS; + +enum { + SD_NDISC_EVENT_STOP = 0, + SD_NDISC_EVENT_TIMEOUT = 1, +}; + +typedef struct sd_ndisc sd_ndisc; + +typedef void(*sd_ndisc_router_callback_t)(sd_ndisc *nd, uint8_t flags, const struct in6_addr *gateway, unsigned lifetime, int pref, void *userdata); +typedef void(*sd_ndisc_prefix_onlink_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, + unsigned lifetime, void *userdata); +typedef void(*sd_ndisc_prefix_autonomous_callback_t)(sd_ndisc *nd, const struct in6_addr *prefix, unsigned prefixlen, + unsigned lifetime_prefered, unsigned lifetime_valid, void *userdata); +typedef void(*sd_ndisc_callback_t)(sd_ndisc *nd, int event, void *userdata); + +int sd_ndisc_set_callback(sd_ndisc *nd, + sd_ndisc_router_callback_t rcb, + sd_ndisc_prefix_onlink_callback_t plcb, + sd_ndisc_prefix_autonomous_callback_t pacb, + sd_ndisc_callback_t cb, + void *userdata); +int sd_ndisc_set_index(sd_ndisc *nd, int interface_index); +int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); + +int sd_ndisc_attach_event(sd_ndisc *nd, sd_event *event, int priority); +int sd_ndisc_detach_event(sd_ndisc *nd); +sd_event *sd_ndisc_get_event(sd_ndisc *nd); + +sd_ndisc *sd_ndisc_ref(sd_ndisc *nd); +sd_ndisc *sd_ndisc_unref(sd_ndisc *nd); +int sd_ndisc_new(sd_ndisc **ret); + +int sd_ndisc_get_mtu(sd_ndisc *nd, uint32_t *mtu); + +int sd_ndisc_stop(sd_ndisc *nd); +int sd_ndisc_router_discovery_start(sd_ndisc *nd); + +#define SD_NDISC_ADDRESS_FORMAT_STR "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" + +#define SD_NDISC_ADDRESS_FORMAT_VAL(address) \ + be16toh((address).s6_addr16[0]), \ + be16toh((address).s6_addr16[1]), \ + be16toh((address).s6_addr16[2]), \ + be16toh((address).s6_addr16[3]), \ + be16toh((address).s6_addr16[4]), \ + be16toh((address).s6_addr16[5]), \ + be16toh((address).s6_addr16[6]), \ + be16toh((address).s6_addr16[7]) + +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref); + +_SD_END_DECLARATIONS; + +#endif diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index eebdb248..26c2ed7f 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -1,8 +1,8 @@ SUBDIRS = config AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -I$(top_srcdir)/src/platform \ @@ -11,10 +11,9 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_builddir)/src \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) + $(GLIB_CFLAGS) noinst_PROGRAMS = \ test-general \ @@ -25,7 +24,8 @@ noinst_PROGRAMS = \ test-route-manager-fake \ test-dcb \ test-resolvconf-capture \ - test-wired-defname + test-wired-defname \ + test-utils ####### ip4 config test ####### @@ -111,6 +111,22 @@ test_wired_defname_SOURCES = \ test_wired_defname_LDADD = \ $(top_builddir)/src/libNetworkManager.la +####### utils test ####### + +test_utils_SOURCES = \ + test-utils.c + +test_utils_DEPENDENCIES = \ + $(top_srcdir)/src/NetworkManagerUtils.c + +test_utils_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DPREFIX=\"/nonexistent\" \ + -DNMSTATEDIR=\"/nonsense\" + +test_utils_LDADD = \ + $(top_builddir)/src/libNetworkManager.la + ####### secret agent interface test ####### EXTRA_DIST = test-secret-agent.py @@ -127,13 +143,14 @@ TESTS = \ test-resolvconf-capture \ test-general \ test-general-with-expect \ - test-wired-defname + test-wired-defname \ + test-utils if ENABLE_TESTS check-local: - @for t in bond bridge ethernet gre infiniband macvlan tun veth vlan vxlan; do \ + @for t in bond bridge ethernet infiniband ip_tunnel macvlan tun veth vlan vxlan; do \ # Ensure the device subclass factory registration constructors exist \ # which could inadvertently break if src/Makefile.am gets changed \ if ! LC_ALL=C nm $(top_builddir)/src/NetworkManager | LC_ALL=C grep -q "register_device_factory_internal_$$t" ; then \ diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in index a4527284..e0967f7b 100644 --- a/src/tests/Makefile.in +++ b/src/tests/Makefile.in @@ -92,12 +92,14 @@ noinst_PROGRAMS = test-general$(EXEEXT) \ test-general-with-expect$(EXEEXT) test-ip4-config$(EXEEXT) \ test-ip6-config$(EXEEXT) test-route-manager-linux$(EXEEXT) \ test-route-manager-fake$(EXEEXT) test-dcb$(EXEEXT) \ - test-resolvconf-capture$(EXEEXT) test-wired-defname$(EXEEXT) + test-resolvconf-capture$(EXEEXT) test-wired-defname$(EXEEXT) \ + test-utils$(EXEEXT) TESTS = test-ip4-config$(EXEEXT) test-ip6-config$(EXEEXT) \ test-route-manager-fake$(EXEEXT) \ test-route-manager-linux$(EXEEXT) test-dcb$(EXEEXT) \ test-resolvconf-capture$(EXEEXT) test-general$(EXEEXT) \ - test-general-with-expect$(EXEEXT) test-wired-defname$(EXEEXT) + test-general-with-expect$(EXEEXT) test-wired-defname$(EXEEXT) \ + test-utils$(EXEEXT) subdir = src/tests ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_lib_readline.m4 \ @@ -165,6 +167,8 @@ test_route_manager_linux_OBJECTS = \ $(am_test_route_manager_linux_OBJECTS) test_route_manager_linux_DEPENDENCIES = \ $(top_builddir)/src/libNetworkManager.la +am_test_utils_OBJECTS = test_utils-test-utils.$(OBJEXT) +test_utils_OBJECTS = $(am_test_utils_OBJECTS) am_test_wired_defname_OBJECTS = test-wired-defname.$(OBJEXT) test_wired_defname_OBJECTS = $(am_test_wired_defname_OBJECTS) test_wired_defname_DEPENDENCIES = \ @@ -207,13 +211,13 @@ SOURCES = $(test_dcb_SOURCES) $(test_general_SOURCES) \ $(test_general_with_expect_SOURCES) $(test_ip4_config_SOURCES) \ $(test_ip6_config_SOURCES) $(test_resolvconf_capture_SOURCES) \ $(test_route_manager_fake_SOURCES) \ - $(test_route_manager_linux_SOURCES) \ + $(test_route_manager_linux_SOURCES) $(test_utils_SOURCES) \ $(test_wired_defname_SOURCES) DIST_SOURCES = $(test_dcb_SOURCES) $(test_general_SOURCES) \ $(test_general_with_expect_SOURCES) $(test_ip4_config_SOURCES) \ $(test_ip6_config_SOURCES) $(test_resolvconf_capture_SOURCES) \ $(test_route_manager_fake_SOURCES) \ - $(test_route_manager_linux_SOURCES) \ + $(test_route_manager_linux_SOURCES) $(test_utils_SOURCES) \ $(test_wired_defname_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ @@ -502,7 +506,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -514,8 +517,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -525,6 +526,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -579,16 +581,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -625,6 +624,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -653,7 +654,6 @@ 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@ @@ -668,6 +668,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -728,6 +730,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -735,6 +738,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -752,8 +756,8 @@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ SUBDIRS = config AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -I$(top_srcdir)/src/platform \ @@ -762,10 +766,9 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_builddir)/src \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ - $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) + $(GLIB_CFLAGS) ####### ip4 config test ####### @@ -852,6 +855,22 @@ test_wired_defname_LDADD = \ $(top_builddir)/src/libNetworkManager.la +####### utils test ####### +test_utils_SOURCES = \ + test-utils.c + +test_utils_DEPENDENCIES = \ + $(top_srcdir)/src/NetworkManagerUtils.c + +test_utils_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DPREFIX=\"/nonexistent\" \ + -DNMSTATEDIR=\"/nonsense\" + +test_utils_LDADD = \ + $(top_builddir)/src/libNetworkManager.la + + ####### secret agent interface test ####### EXTRA_DIST = test-secret-agent.py all: all-recursive @@ -929,6 +948,10 @@ test-route-manager-linux$(EXEEXT): $(test_route_manager_linux_OBJECTS) $(test_ro @rm -f test-route-manager-linux$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_route_manager_linux_OBJECTS) $(test_route_manager_linux_LDADD) $(LIBS) +test-utils$(EXEEXT): $(test_utils_OBJECTS) $(test_utils_DEPENDENCIES) $(EXTRA_test_utils_DEPENDENCIES) + @rm -f test-utils$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(test_utils_OBJECTS) $(test_utils_LDADD) $(LIBS) + test-wired-defname$(EXEEXT): $(test_wired_defname_OBJECTS) $(test_wired_defname_DEPENDENCIES) $(EXTRA_test_wired_defname_DEPENDENCIES) @rm -f test-wired-defname$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_wired_defname_OBJECTS) $(test_wired_defname_LDADD) $(LIBS) @@ -950,6 +973,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_route_manager_fake-test-route-manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_route_manager_linux-test-common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_route_manager_linux-test-route-manager.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_utils-test-utils.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @@ -1028,6 +1052,20 @@ test_route_manager_linux-test-route-manager.obj: test-route-manager.c @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_manager_linux_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_route_manager_linux-test-route-manager.obj `if test -f 'test-route-manager.c'; then $(CYGPATH_W) 'test-route-manager.c'; else $(CYGPATH_W) '$(srcdir)/test-route-manager.c'; fi` +test_utils-test-utils.o: test-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_utils_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_utils-test-utils.o -MD -MP -MF $(DEPDIR)/test_utils-test-utils.Tpo -c -o test_utils-test-utils.o `test -f 'test-utils.c' || echo '$(srcdir)/'`test-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_utils-test-utils.Tpo $(DEPDIR)/test_utils-test-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-utils.c' object='test_utils-test-utils.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_utils_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_utils-test-utils.o `test -f 'test-utils.c' || echo '$(srcdir)/'`test-utils.c + +test_utils-test-utils.obj: test-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_utils_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT test_utils-test-utils.obj -MD -MP -MF $(DEPDIR)/test_utils-test-utils.Tpo -c -o test_utils-test-utils.obj `if test -f 'test-utils.c'; then $(CYGPATH_W) 'test-utils.c'; else $(CYGPATH_W) '$(srcdir)/test-utils.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/test_utils-test-utils.Tpo $(DEPDIR)/test_utils-test-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-utils.c' object='test_utils-test-utils.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_utils_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o test_utils-test-utils.obj `if test -f 'test-utils.c'; then $(CYGPATH_W) 'test-utils.c'; else $(CYGPATH_W) '$(srcdir)/test-utils.c'; fi` + mostlyclean-libtool: -rm -f *.lo @@ -1337,6 +1375,13 @@ test-wired-defname.log: test-wired-defname$(EXEEXT) --log-file $$b.log --trs-file $$b.trs \ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ "$$tst" $(AM_TESTS_FD_REDIRECT) +test-utils.log: test-utils$(EXEEXT) + @p='test-utils$(EXEEXT)'; \ + b='test-utils'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) .test.log: @p='$<'; \ $(am__set_b); \ @@ -1543,7 +1588,7 @@ uninstall-am: @VALGRIND_RULES@ @ENABLE_TESTS_TRUE@check-local: -@ENABLE_TESTS_TRUE@ @for t in bond bridge ethernet gre infiniband macvlan tun veth vlan vxlan; do \ +@ENABLE_TESTS_TRUE@ @for t in bond bridge ethernet infiniband ip_tunnel macvlan tun veth vlan vxlan; do \ @ENABLE_TESTS_TRUE@ # Ensure the device subclass factory registration constructors exist \ @ENABLE_TESTS_TRUE@ # which could inadvertently break if src/Makefile.am gets changed \ @ENABLE_TESTS_TRUE@ if ! LC_ALL=C nm $(top_builddir)/src/NetworkManager | LC_ALL=C grep -q "register_device_factory_internal_$$t" ; then \ diff --git a/src/tests/config/Makefile.am b/src/tests/config/Makefile.am index a5e068e4..5d4aed5c 100644 --- a/src/tests/config/Makefile.am +++ b/src/tests/config/Makefile.am @@ -1,17 +1,17 @@ AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -I$(top_srcdir)/src/ \ -I$(top_srcdir)/src/devices \ -I${top_srcdir}/src/platform \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) \ - -DSRCDIR=\""$(srcdir)"\" + -DSRCDIR=\""$(srcdir)"\" \ + -DBUILDDIR=\""$(builddir)"\" noinst_PROGRAMS = \ test-config @@ -30,6 +30,8 @@ TESTS = test-config EXTRA_DIST = \ NetworkManager.conf \ bad.conf \ + global-dns-invalid.conf \ conf.d/00-overrides.conf \ conf.d/10-more.conf \ + conf.d/20-config-enable-1.conf \ conf.d/90-last.conf diff --git a/src/tests/config/Makefile.in b/src/tests/config/Makefile.in index 20bbe60a..994e7068 100644 --- a/src/tests/config/Makefile.in +++ b/src/tests/config/Makefile.in @@ -403,7 +403,6 @@ BLUEZ5_LIBS = @BLUEZ5_LIBS@ 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@ @@ -415,8 +414,6 @@ CXXDEPMODE = @CXXDEPMODE@ CXXFLAGS = @CXXFLAGS@ CYGPATH_W = @CYGPATH_W@ 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@ @@ -426,6 +423,7 @@ DHCPCD_PATH = @DHCPCD_PATH@ DISTRO_NETWORK_SERVICE = @DISTRO_NETWORK_SERVICE@ DLLTOOL = @DLLTOOL@ DNSMASQ_PATH = @DNSMASQ_PATH@ +DNSSEC_TRIGGER_SCRIPT = @DNSSEC_TRIGGER_SCRIPT@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -480,16 +478,13 @@ 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@ +LIBAUDIT_CFLAGS = @LIBAUDIT_CFLAGS@ +LIBAUDIT_LIBS = @LIBAUDIT_LIBS@ LIBDL = @LIBDL@ -LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ -LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ -LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBM = @LIBM@ @@ -526,6 +521,8 @@ NEWT_LIBS = @NEWT_LIBS@ NM = @NM@ NMEDIT = @NMEDIT@ NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT = @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@ +NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT = @NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT@ +NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT = @NM_CONFIG_LOGGING_BACKEND_DEFAULT_TEXT@ NM_MAJOR_VERSION = @NM_MAJOR_VERSION@ NM_MICRO_VERSION = @NM_MICRO_VERSION@ NM_MINOR_VERSION = @NM_MINOR_VERSION@ @@ -554,7 +551,6 @@ 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@ @@ -569,6 +565,8 @@ 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_JOURNAL_CFLAGS = @SYSTEMD_JOURNAL_CFLAGS@ +SYSTEMD_JOURNAL_LIBS = @SYSTEMD_JOURNAL_LIBS@ SYSTEMD_LOGIN_CFLAGS = @SYSTEMD_LOGIN_CFLAGS@ SYSTEMD_LOGIN_LIBS = @SYSTEMD_LOGIN_LIBS@ SYSTEM_CA_PATH = @SYSTEM_CA_PATH@ @@ -629,6 +627,7 @@ mkdir_p = @mkdir_p@ nmbinary = @nmbinary@ nmconfdir = @nmconfdir@ nmdatadir = @nmdatadir@ +nmlibdir = @nmlibdir@ nmrundir = @nmrundir@ nmstatedir = @nmstatedir@ oldincludedir = @oldincludedir@ @@ -636,6 +635,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -652,19 +652,19 @@ with_netconfig = @with_netconfig@ with_resolvconf = @with_resolvconf@ with_valgrind = @with_valgrind@ AM_CPPFLAGS = \ - -I$(top_srcdir)/include \ - -I$(top_builddir)/include \ + -I$(top_srcdir)/shared \ + -I$(top_builddir)/shared \ -I$(top_srcdir)/libnm-core \ -I$(top_builddir)/libnm-core \ -I$(top_srcdir)/src/ \ -I$(top_srcdir)/src/devices \ -I${top_srcdir}/src/platform \ -DG_LOG_DOMAIN=\""NetworkManager"\" \ - -DNETWORKMANAGER_COMPILATION \ + -DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) \ - $(DBUS_CFLAGS) \ - -DSRCDIR=\""$(srcdir)"\" + -DSRCDIR=\""$(srcdir)"\" \ + -DBUILDDIR=\""$(builddir)"\" test_config_SOURCES = \ nm-test-device.c \ @@ -677,8 +677,10 @@ test_config_LDADD = \ EXTRA_DIST = \ NetworkManager.conf \ bad.conf \ + global-dns-invalid.conf \ conf.d/00-overrides.conf \ conf.d/10-more.conf \ + conf.d/20-config-enable-1.conf \ conf.d/90-last.conf all: all-am diff --git a/src/tests/config/NetworkManager.conf b/src/tests/config/NetworkManager.conf index a750c801..da7b1fd4 100644 --- a/src/tests/config/NetworkManager.conf +++ b/src/tests/config/NetworkManager.conf @@ -81,3 +81,19 @@ ord.key07=A-0.3.07 ord.key08=A-0.3.08 ord.key09=A-0.3.09 ord.ovw01=A-0.3.ovw01 + +[global-dns] +enable=yes +searches=foo.com,bar.org +options=debug,edns0 + +[global-dns-domain-*] +servers=1.1.1.1,bad,1::128 +options=opt1,opt2 + +[global-dns-domain-example.com] +servers=2.2.2.2 + +# Invalid section: 'servers' key is missing +[global-dns-domain-test.com] +options=opt3 diff --git a/src/tests/config/conf.d/20-config-enable-1.conf b/src/tests/config/conf.d/20-config-enable-1.conf new file mode 100644 index 00000000..e6800f52 --- /dev/null +++ b/src/tests/config/conf.d/20-config-enable-1.conf @@ -0,0 +1,5 @@ +[.config] +enable=nm-version:1.5.32,env:test-match-env-1 + +[test-group-config-enable-1] +key1=enabled diff --git a/src/tests/config/global-dns-invalid.conf b/src/tests/config/global-dns-invalid.conf new file mode 100644 index 00000000..e490f609 --- /dev/null +++ b/src/tests/config/global-dns-invalid.conf @@ -0,0 +1,9 @@ +# Invalid configuration, since there isn't a default domain section + +[global-dns] +searches=foo.com +options=timeout:5 + +[global-dns-domain-test.com] +servers=1.2.3.4 +options=myoption diff --git a/src/tests/config/nm-test-device.h b/src/tests/config/nm-test-device.h index 00b21c42..c3532c9c 100644 --- a/src/tests/config/nm-test-device.h +++ b/src/tests/config/nm-test-device.h @@ -21,7 +21,7 @@ #ifndef __NETWORKMANAGER_TEST_DEVICE_H__ #define __NETWORKMANAGER_TEST_DEVICE_H__ -#include +#include "nm-device.h" G_BEGIN_DECLS diff --git a/src/tests/config/test-config.c b/src/tests/config/test-config.c index 6dad8216..e8de86c8 100644 --- a/src/tests/config/test-config.c +++ b/src/tests/config/test-config.c @@ -22,18 +22,36 @@ #include -#include -#include +#include "nm-config.h" +#include "nm-default.h" #include "nm-test-device.h" #include "nm-fake-platform.h" -#include "nm-logging.h" -#include "nm-dbus-manager.h" +#include "nm-bus-manager.h" #include "nm-test-utils.h" +/********************************************************************************/ + +static void +_assert_config_value (const NMConfigData *config_data, const char *group, const char *key, const char *expected_value, const char *file, int line) +{ + gs_free char *value = NULL; + + value = nm_config_data_get_value (config_data, group, key, NM_CONFIG_GET_VALUE_NONE); + if (g_strcmp0 (value, expected_value)) { + g_error ("(%s:%d) invalid value in config-data %s.%s = %s%s%s (instead of %s%s%s)", + file, line, group, key, + NM_PRINT_FMT_QUOTED (value, "\"", value, "\"", "(null)"), + NM_PRINT_FMT_QUOTED (expected_value, "\"", expected_value, "\"", "(null)")); + } +} +#define assert_config_value(config_data, group, key, expected_value) _assert_config_value (config_data, group, key, expected_value, __FILE__, __LINE__) + +/********************************************************************************/ + static NMConfig * -setup_config (GError **error, const char *config_file, const char *config_dir, ...) +setup_config (GError **error, const char *config_file, const char *intern_config, const char *const* atomic_section_prefixes, const char *config_dir, const char *system_config_dir, ...) { va_list ap; GPtrArray *args; @@ -51,10 +69,18 @@ setup_config (GError **error, const char *config_file, const char *config_dir, . g_ptr_array_add (args, "test-config"); g_ptr_array_add (args, "--config"); g_ptr_array_add (args, (char *)config_file); + if (intern_config) { + g_ptr_array_add (args, "--intern-config"); + g_ptr_array_add (args, (char *)intern_config); + } g_ptr_array_add (args, "--config-dir"); g_ptr_array_add (args, (char *)config_dir); + if (system_config_dir) { + g_ptr_array_add (args, "--system-config-dir"); + g_ptr_array_add (args, (char *) system_config_dir); + } - va_start (ap, config_dir); + va_start (ap, system_config_dir); while ((arg = va_arg (ap, char *))) g_ptr_array_add (args, arg); va_end (ap); @@ -74,7 +100,7 @@ setup_config (GError **error, const char *config_file, const char *config_dir, . g_ptr_array_free (args, TRUE); - config = nm_config_setup (cli, &local_error); + config = nm_config_setup (cli, (char **) atomic_section_prefixes, &local_error); if (error) { g_assert (!config); g_assert (local_error); @@ -97,7 +123,7 @@ test_config_simple (void) gs_unref_object NMDevice *dev51 = nm_test_device_new ("00:00:00:00:00:51"); gs_unref_object NMDevice *dev52 = nm_test_device_new ("00:00:00:00:00:52"); - config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir", NULL); + config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, "/no/such/dir", "", NULL); g_assert_cmpstr (nm_config_data_get_config_main_file (nm_config_get_data_orig (config)), ==, SRCDIR "/NetworkManager.conf"); g_assert_cmpstr (nm_config_get_dhcp_client (config), ==, "dhclient"); @@ -174,9 +200,9 @@ test_config_simple (void) static void test_config_non_existent (void) { - gs_free_error GError *error = NULL; + GError *error = NULL; - setup_config (&error, SRCDIR "/no-such-file", "/no/such/dir", NULL); + setup_config (&error, SRCDIR "/no-such-file", "", NULL, "/no/such/dir", "", NULL); g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND); g_clear_error (&error); } @@ -184,9 +210,9 @@ test_config_non_existent (void) static void test_config_parse_error (void) { - gs_free_error GError *error = NULL; + GError *error = NULL; - setup_config (&error, SRCDIR "/bad.conf", "/no/such/dir", NULL); + setup_config (&error, SRCDIR "/bad.conf", "", NULL, "/no/such/dir", "", NULL); g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE); g_clear_error (&error); } @@ -197,7 +223,7 @@ test_config_override (void) NMConfig *config; const char **plugins; - config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir", + config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, "/no/such/dir", "", "--plugins", "alpha,beta,gamma,delta", "--connectivity-interval", "12", NULL); @@ -217,6 +243,76 @@ test_config_override (void) g_object_unref (config); } +static void +test_config_global_dns (void) +{ + NMConfig *config; + const NMGlobalDnsConfig *dns; + NMGlobalDnsDomain *domain; + const char *const *strv; + + config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, + "/no/such/dir", "", NULL); + + dns = nm_config_data_get_global_dns_config (nm_config_get_data_orig (config)); + g_assert (dns); + + strv = nm_global_dns_config_get_searches (dns); + g_assert (strv); + g_assert_cmpuint (g_strv_length ((char **) strv), ==, 2); + g_assert_cmpstr (strv[0], ==, "foo.com"); + g_assert_cmpstr (strv[1], ==, "bar.org"); + + strv = nm_global_dns_config_get_options (dns); + g_assert (strv); + g_assert_cmpuint (g_strv_length ((char **) strv), ==, 2); + g_assert_cmpstr (strv[0], ==, "debug"); + g_assert_cmpstr (strv[1], ==, "edns0"); + + g_assert_cmpuint (nm_global_dns_config_get_num_domains (dns), ==, 2); + + /* Default domain */ + domain = nm_global_dns_config_lookup_domain (dns, "*"); + g_assert (domain); + + strv = nm_global_dns_domain_get_servers (domain); + g_assert (strv); + g_assert_cmpuint (g_strv_length ((char **) strv), ==, 2); + g_assert_cmpstr (strv[0], ==, "1.1.1.1"); + g_assert_cmpstr (strv[1], ==, "1::128"); + + strv = nm_global_dns_domain_get_options (domain); + g_assert (strv); + g_assert_cmpuint (g_strv_length ((char **) strv), ==, 2); + g_assert_cmpstr (strv[0], ==, "opt1"); + g_assert_cmpstr (strv[1], ==, "opt2"); + + /* 'example.com' domain */ + domain = nm_global_dns_config_lookup_domain (dns, "example.com"); + g_assert (domain); + + strv = nm_global_dns_domain_get_servers (domain); + g_assert (strv); + g_assert_cmpuint (g_strv_length ((char **) strv), ==, 1); + g_assert_cmpstr (strv[0], ==, "2.2.2.2"); + + strv = nm_global_dns_domain_get_options (domain); + g_assert (!strv || g_strv_length ((char **) strv) == 0); + + /* Non-existent domain 'test.com' */ + domain = nm_global_dns_config_lookup_domain (dns, "test.com"); + g_assert (!domain); + + g_object_unref (config); + + /* Check that a file without a default domain section gives a NULL configuration */ + config = setup_config (NULL, SRCDIR "/global-dns-invalid.conf", "", NULL, + "/no/such/dir", "", NULL); + dns = nm_config_data_get_global_dns_config (nm_config_get_data_orig (config)); + g_assert (!dns); + g_object_unref (config); +} + static void test_config_no_auto_default (void) { @@ -235,7 +331,7 @@ test_config_no_auto_default (void) g_assert_cmpint (nwrote, ==, 18); close (fd); - config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir", + config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, "/no/such/dir", "", "--no-auto-default", state_file, NULL); @@ -257,7 +353,7 @@ test_config_no_auto_default (void) g_object_unref (config); - config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir", + config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, "/no/such/dir", "", "--no-auto-default", state_file, NULL); @@ -285,7 +381,7 @@ test_config_confdir (void) char *value; GSList *specs; - config = setup_config (NULL, SRCDIR "/NetworkManager.conf", SRCDIR "/conf.d", NULL); + config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, SRCDIR "/conf.d", "", NULL); g_assert_cmpstr (nm_config_data_get_config_main_file (nm_config_get_data_orig (config)), ==, SRCDIR "/NetworkManager.conf"); g_assert_cmpstr (nm_config_get_dhcp_client (config), ==, "dhcpcd"); @@ -391,13 +487,336 @@ test_config_confdir_parse_error (void) GError *error = NULL; /* Using SRCDIR as the conf dir will pick up bad.conf */ - setup_config (&error, SRCDIR "/NetworkManager.conf", SRCDIR, NULL); + setup_config (&error, SRCDIR "/NetworkManager.conf", "", NULL, SRCDIR, "", NULL); g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE); g_clear_error (&error); } /*****************************************************************************/ +typedef void (*TestSetValuesUserSetFcn) (NMConfig *config, gboolean is_user, GKeyFile *keyfile_user, NMConfigChangeFlags *out_expected_changes); +typedef void (*TestSetValuesCheckStateFcn) (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data); + +typedef struct { + NMConfigChangeFlags changes; + TestSetValuesCheckStateFcn check_state_fcn; +} TestSetValuesConfigChangedData; + +static void +_set_values_config_changed_cb (NMConfig *config, + NMConfigData *config_data, + NMConfigChangeFlags changes, + NMConfigData *old_data, + TestSetValuesConfigChangedData *config_changed_data) +{ + g_assert (changes != NM_CONFIG_CHANGE_NONE); + g_assert (config_changed_data); + g_assert (config_changed_data->changes == NM_CONFIG_CHANGE_NONE); + + if (changes == NM_CONFIG_CHANGE_SIGHUP) + return; + changes &= ~NM_CONFIG_CHANGE_SIGHUP; + + config_changed_data->changes = changes; + + if (config_changed_data->check_state_fcn) + config_changed_data->check_state_fcn (config, config_data, TRUE, changes, old_data); +} + +static void +_set_values_user (NMConfig *config, + const char *CONFIG_USER, + TestSetValuesUserSetFcn set_fcn, + TestSetValuesCheckStateFcn check_state_fcn) +{ + GKeyFile *keyfile_user; + gboolean success; + gs_free_error GError *error = NULL; + TestSetValuesConfigChangedData config_changed_data = { + .changes = NM_CONFIG_CHANGE_NONE, + .check_state_fcn = check_state_fcn, + }; + NMConfigChangeFlags expected_changes = NM_CONFIG_CHANGE_NONE; + gs_unref_object NMConfigData *config_data_before = NULL; + + keyfile_user = nm_config_create_keyfile (); + + success = g_key_file_load_from_file (keyfile_user, CONFIG_USER, G_KEY_FILE_NONE, &error); + nmtst_assert_success (success, error); + + if (set_fcn) + set_fcn (config, TRUE, keyfile_user, &expected_changes); + + success = g_key_file_save_to_file (keyfile_user, CONFIG_USER, &error); + nmtst_assert_success (success, error); + + g_signal_connect (G_OBJECT (config), + NM_CONFIG_SIGNAL_CONFIG_CHANGED, + G_CALLBACK (_set_values_config_changed_cb), + &config_changed_data); + + config_data_before = g_object_ref (nm_config_get_data (config)); + + if (expected_changes != NM_CONFIG_CHANGE_NONE) + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*config: update *"); + else + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*config: signal SIGHUP (no changes from disk)*"); + + nm_config_reload (config, SIGHUP); + + g_test_assert_expected_messages (); + + g_assert (expected_changes == config_changed_data.changes); + + if (check_state_fcn) + check_state_fcn (config, nm_config_get_data (config), FALSE, NM_CONFIG_CHANGE_NONE, config_data_before); + + g_signal_handlers_disconnect_by_func (config, _set_values_config_changed_cb, &config_changed_data); + + g_key_file_unref (keyfile_user); +} + +static void +_set_values_intern (NMConfig *config, + TestSetValuesUserSetFcn set_fcn, + TestSetValuesCheckStateFcn check_state_fcn) +{ + GKeyFile *keyfile_intern; + TestSetValuesConfigChangedData config_changed_data = { + .changes = NM_CONFIG_CHANGE_NONE, + .check_state_fcn = check_state_fcn, + }; + NMConfigChangeFlags expected_changes = NM_CONFIG_CHANGE_NONE; + gs_unref_object NMConfigData *config_data_before = NULL; + + config_data_before = g_object_ref (nm_config_get_data (config)); + + keyfile_intern = nm_config_data_clone_keyfile_intern (config_data_before); + + if (set_fcn) + set_fcn (config, FALSE, keyfile_intern, &expected_changes); + + g_signal_connect (G_OBJECT (config), + NM_CONFIG_SIGNAL_CONFIG_CHANGED, + G_CALLBACK (_set_values_config_changed_cb), + &config_changed_data); + + if (expected_changes != NM_CONFIG_CHANGE_NONE) + g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*config: update *"); + + nm_config_set_values (config, keyfile_intern, TRUE, FALSE); + + g_test_assert_expected_messages (); + + g_assert (expected_changes == config_changed_data.changes); + + if (check_state_fcn) + check_state_fcn (config, nm_config_get_data (config), FALSE, NM_CONFIG_CHANGE_NONE, config_data_before); + + g_signal_handlers_disconnect_by_func (config, _set_values_config_changed_cb, &config_changed_data); + + g_key_file_unref (keyfile_intern); +} + +static void +_set_values_user_intern_section_set (NMConfig *config, gboolean set_user, GKeyFile *keyfile, NMConfigChangeFlags *out_expected_changes) +{ + g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"section1", "key", "this-should-be-ignored"); +} + +static void +_set_values_user_intern_section_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data) +{ + g_assert (changes == NM_CONFIG_CHANGE_NONE); + g_assert (!nm_config_data_has_group (config_data, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"section1")); +} + +static void +_set_values_user_initial_values_set (NMConfig *config, gboolean set_user, GKeyFile *keyfile, NMConfigChangeFlags *out_expected_changes) +{ + g_key_file_remove_group (keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"section1", NULL); + g_key_file_set_string (keyfile, "section1", "key1", "value1"); + *out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER; +} + +static void +_set_values_user_initial_values_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data) +{ + if (is_change_event) + g_assert (changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER)); + assert_config_value (config_data, "section1", "key1", "value1"); +} + +static void +_set_values_intern_internal_set (NMConfig *config, gboolean set_user, GKeyFile *keyfile, NMConfigChangeFlags *out_expected_changes) +{ + g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"section1", "key", "internal-section"); + *out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN; +} + +static void +_set_values_intern_internal_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data) +{ + if (is_change_event) + g_assert (changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN)); + assert_config_value (config_data, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"section1", "key", "internal-section"); +} + +static void +_set_values_user_atomic_section_1_set (NMConfig *config, gboolean set_user, GKeyFile *keyfile, NMConfigChangeFlags *out_expected_changes) +{ + g_key_file_set_string (keyfile, "atomic-prefix-1.section-a", "key1", "user-value1"); + g_key_file_set_string (keyfile, "atomic-prefix-1.section-a", "key2", "user-value2"); + g_key_file_set_string (keyfile, "atomic-prefix-1.section-b", "key1", "user-value1"); + g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key1", "user-value1"); + g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key2", "user-value2"); + *out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER; +} + +static void +_set_values_user_atomic_section_1_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data) +{ + if (is_change_event) + g_assert (changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER)); + assert_config_value (config_data, "atomic-prefix-1.section-a", "key1", "user-value1"); + assert_config_value (config_data, "atomic-prefix-1.section-a", "key2", "user-value2"); + assert_config_value (config_data, "atomic-prefix-1.section-b", "key1", "user-value1"); + assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key1", "user-value1"); + assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key2", "user-value2"); +} + +static void +_set_values_intern_atomic_section_1_set (NMConfig *config, gboolean set_user, GKeyFile *keyfile, NMConfigChangeFlags *out_expected_changes) +{ + g_key_file_set_string (keyfile, "atomic-prefix-1.section-a", "key1", "intern-value1"); + g_key_file_set_string (keyfile, "atomic-prefix-1.section-a", "key3", "intern-value3"); + g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key1", "intern-value1"); + g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key3", "intern-value3"); + *out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN; +} + +static void +_set_values_intern_atomic_section_1_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data) +{ + if (is_change_event) + g_assert (changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN)); + assert_config_value (config_data, "atomic-prefix-1.section-a", "key1", "intern-value1"); + assert_config_value (config_data, "atomic-prefix-1.section-a", "key2", NULL); + assert_config_value (config_data, "atomic-prefix-1.section-a", "key3", "intern-value3"); + assert_config_value (config_data, "atomic-prefix-1.section-b", "key1", "user-value1"); + assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key1", "intern-value1"); + assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key2", "user-value2"); + assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key3", "intern-value3"); + g_assert ( nm_config_data_is_intern_atomic_group (config_data, "atomic-prefix-1.section-a")); + g_assert (!nm_config_data_is_intern_atomic_group (config_data, "atomic-prefix-1.section-b")); + g_assert (!nm_config_data_is_intern_atomic_group (config_data, "non-atomic-prefix-1.section-a")); +} + +static void +_set_values_user_atomic_section_2_set (NMConfig *config, gboolean set_user, GKeyFile *keyfile, NMConfigChangeFlags *out_expected_changes) +{ + g_key_file_set_string (keyfile, "atomic-prefix-1.section-a", "key1", "user-value1-x"); + g_key_file_set_string (keyfile, "atomic-prefix-1.section-a", "key2", "user-value2"); + g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key1", "user-value1-x"); + g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key2", "user-value2-x"); + *out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER | NM_CONFIG_CHANGE_VALUES_INTERN; +} + +static void +_set_values_user_atomic_section_2_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data) +{ + if (is_change_event) + g_assert (changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_USER | NM_CONFIG_CHANGE_VALUES_INTERN)); + assert_config_value (config_data, "atomic-prefix-1.section-a", "key1", "user-value1-x"); + assert_config_value (config_data, "atomic-prefix-1.section-a", "key2", "user-value2"); + assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key1", "user-value1-x"); + assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key2", "user-value2-x"); + assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key3", "intern-value3"); + g_assert (!nm_config_data_is_intern_atomic_group (config_data, "atomic-prefix-1.section-a")); + g_assert (!nm_config_data_is_intern_atomic_group (config_data, "atomic-prefix-1.section-b")); + g_assert (!nm_config_data_is_intern_atomic_group (config_data, "non-atomic-prefix-1.section-a")); +} + +static void +_set_values_intern_atomic_section_2_set (NMConfig *config, gboolean set_user, GKeyFile *keyfile, NMConfigChangeFlags *out_expected_changes) +{ + /* let's hide an atomic section and one key. */ + g_key_file_set_string (keyfile, "atomic-prefix-1.section-a", NM_CONFIG_KEYFILE_KEY_ATOMIC_SECTION_WAS, "any-value"); + g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", NM_CONFIG_KEYFILE_KEYPREFIX_WAS"nap1-key1", "any-value"); + g_key_file_set_string (keyfile, "non-atomic-prefix-1.section-a", "nap1-key3", "intern-value3"); + g_key_file_set_string (keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"with-whitespace", "key1", " b c\\, d "); + g_key_file_set_value (keyfile, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"with-whitespace", "key2", " b c\\, d "); + *out_expected_changes = NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN; +} + +static void +_set_values_intern_atomic_section_2_check (NMConfig *config, NMConfigData *config_data, gboolean is_change_event, NMConfigChangeFlags changes, NMConfigData *old_data) +{ + if (is_change_event) + g_assert (changes == (NM_CONFIG_CHANGE_VALUES | NM_CONFIG_CHANGE_VALUES_INTERN)); + g_assert (!nm_config_data_has_group (config_data, "atomic-prefix-1.section-a")); + assert_config_value (config_data, "atomic-prefix-1.section-b", "key1", "user-value1"); + assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key1", NULL); + assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key2", "user-value2-x"); + assert_config_value (config_data, "non-atomic-prefix-1.section-a", "nap1-key3", "intern-value3"); + g_assert (!nm_config_data_is_intern_atomic_group (config_data, "atomic-prefix-1.section-a")); + g_assert (!nm_config_data_is_intern_atomic_group (config_data, "atomic-prefix-1.section-b")); + g_assert (!nm_config_data_is_intern_atomic_group (config_data, "non-atomic-prefix-1.section-a")); + assert_config_value (config_data, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"with-whitespace", "key1", " b c\\, d "); + assert_config_value (config_data, NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN"with-whitespace", "key2", " b c\\, d "); +} + +static void +test_config_set_values (void) +{ + gs_unref_object NMConfig *config = NULL; + const char *CONFIG_USER = BUILDDIR"/test-set-values-user.conf"; + const char *CONFIG_INTERN = BUILDDIR"/test-set-values-intern.conf"; + const char *atomic_section_prefixes[] = { + "atomic-prefix-1.", + "atomic-prefix-2.", + NULL, + }; + + g_assert (g_file_set_contents (CONFIG_USER, "", 0, NULL)); + g_assert (g_file_set_contents (CONFIG_INTERN, "", 0, NULL)); + + config = setup_config (NULL, CONFIG_USER, CONFIG_INTERN, atomic_section_prefixes, "", "", NULL); + + _set_values_user (config, CONFIG_USER, + _set_values_user_intern_section_set, + _set_values_user_intern_section_check); + + _set_values_user (config, CONFIG_USER, + _set_values_user_initial_values_set, + _set_values_user_initial_values_check); + + _set_values_intern (config, + _set_values_intern_internal_set, + _set_values_intern_internal_check); + + _set_values_user (config, CONFIG_USER, + _set_values_user_atomic_section_1_set, + _set_values_user_atomic_section_1_check); + + _set_values_intern (config, + _set_values_intern_atomic_section_1_set, + _set_values_intern_atomic_section_1_check); + + _set_values_user (config, CONFIG_USER, + _set_values_user_atomic_section_2_set, + _set_values_user_atomic_section_2_check); + + _set_values_intern (config, + _set_values_intern_atomic_section_2_set, + _set_values_intern_atomic_section_2_check); + + g_assert (remove (CONFIG_USER) == 0); + g_assert (remove (CONFIG_INTERN) == 0); +} + +/*****************************************************************************/ + static void _test_signal_config_changed_cb (NMConfig *config, NMConfigData *config_data, @@ -436,7 +855,7 @@ test_config_signal (void) NMConfigChangeFlags expected; gs_unref_object NMConfigData *config_data_orig = NULL; - config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir", NULL); + config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, SRCDIR "/conf.d", "", NULL); config_data_orig = g_object_ref (nm_config_get_data_orig (config)); @@ -479,6 +898,40 @@ test_config_signal (void) /*****************************************************************************/ +static void +test_config_enable (void) +{ + gs_unref_object NMConfig *config = NULL; + guint match_nm_version = _nm_config_match_nm_version; + char *match_env = g_strdup (_nm_config_match_env); + + g_clear_pointer (&_nm_config_match_env, g_free); + _nm_config_match_env = g_strdup ("something-else"); + + _nm_config_match_nm_version = nm_encode_version (1, 3, 4); + config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, SRCDIR "/conf.d", "", NULL); + assert_config_value (nm_config_get_data_orig (config), "test-group-config-enable-1", "key1", NULL); + g_clear_object (&config); + + _nm_config_match_nm_version = nm_encode_version (1, 5, 32); + config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, SRCDIR "/conf.d", "", NULL); + assert_config_value (nm_config_get_data_orig (config), "test-group-config-enable-1", "key1", "enabled"); + g_clear_object (&config); + + _nm_config_match_nm_version = nm_encode_version (1, 5, 3); + g_clear_pointer (&_nm_config_match_env, g_free); + _nm_config_match_env = g_strdup ("test-match-env-1"); + config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "", NULL, SRCDIR "/conf.d", "", NULL); + assert_config_value (nm_config_get_data_orig (config), "test-group-config-enable-1", "key1", "enabled"); + g_clear_object (&config); + + _nm_config_match_nm_version = match_nm_version; + g_clear_pointer (&_nm_config_match_env, g_free); + _nm_config_match_env = match_env; +} + +/*****************************************************************************/ + NMTST_DEFINE (); int @@ -488,10 +941,10 @@ main (int argc, char **argv) /* Initialize the DBus manager singleton explicitly, because it is accessed by * the class initializer of NMDevice (used by the NMTestDevice stub). - * This way, we skip calling nm_dbus_manager_init_bus() which would + * This way, we skip calling nm_bus_manager_init_bus() which would * either fail and/or cause unexpected actions in the test. * */ - nm_dbus_manager_setup (g_object_new (NM_TYPE_DBUS_MANAGER, NULL)); + nm_bus_manager_setup (g_object_new (NM_TYPE_BUS_MANAGER, NULL)); nm_fake_platform_setup (); @@ -502,8 +955,13 @@ main (int argc, char **argv) g_test_add_func ("/config/confdir", test_config_confdir); g_test_add_func ("/config/confdir-parse-error", test_config_confdir_parse_error); + g_test_add_func ("/config/set-values", test_config_set_values); + g_test_add_func ("/config/global-dns", test_config_global_dns); + g_test_add_func ("/config/signal", test_config_signal); + g_test_add_func ("/config/enable", test_config_enable); + /* This one has to come last, because it leaves its values in * nm-config.c's global variables, and there's no way to reset * those to NULL. diff --git a/src/tests/test-dcb.c b/src/tests/test-dcb.c index dacb1f52..35f1ed0f 100644 --- a/src/tests/test-dcb.c +++ b/src/tests/test-dcb.c @@ -20,11 +20,13 @@ #include "config.h" -#include #include +#include "nm-default.h" #include "nm-dcb.h" +#include "nm-test-utils.h" + typedef struct { guint num; const char *cmds[]; @@ -335,14 +337,12 @@ test_fcoe_cleanup (void) /*******************************************/ +NMTST_DEFINE (); + int main (int argc, char **argv) { - g_test_init (&argc, &argv, NULL); - -#if !GLIB_CHECK_VERSION (2, 35, 0) - g_type_init (); -#endif + nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); g_test_add_func ("/dcb/fcoe", test_dcb_fcoe); g_test_add_func ("/dcb/iscsi", test_dcb_iscsi); diff --git a/src/tests/test-general-with-expect.c b/src/tests/test-general-with-expect.c index 21fb0681..c6abdccf 100644 --- a/src/tests/test-general-with-expect.c +++ b/src/tests/test-general-with-expect.c @@ -20,7 +20,6 @@ #include "config.h" -#include #include #include #include @@ -28,8 +27,8 @@ #include #include +#include "nm-default.h" #include "NetworkManagerUtils.h" -#include "nm-logging.h" #include "nm-multi-index.h" #include "nm-test-utils.h" @@ -865,9 +864,9 @@ main (int argc, char **argv) g_test_add_func ("/general/nm_utils_monotonic_timestamp_as_boottime", test_nm_utils_monotonic_timestamp_as_boottime); g_test_add_func ("/general/nm_utils_kill_child", test_nm_utils_kill_child); + g_test_add_func ("/general/nm_utils_array_remove_at_indexes", test_nm_utils_array_remove_at_indexes); g_test_add_func ("/general/nm_ethernet_address_is_valid", test_nm_ethernet_address_is_valid); g_test_add_func ("/general/nm_multi_index", test_nm_multi_index); - g_test_add_func ("/general/nm_utils_array_remove_at_indexes", test_nm_utils_array_remove_at_indexes); return g_test_run (); } diff --git a/src/tests/test-general.c b/src/tests/test-general.c index 094a4a65..da68c9a9 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -20,12 +20,11 @@ #include "config.h" -#include #include #include +#include "nm-default.h" #include "NetworkManagerUtils.h" -#include "nm-logging.h" #include "nm-core-internal.h" #include "nm-test-utils.h" @@ -574,6 +573,62 @@ test_connection_no_match_ip4_addr (void) g_object_unref (copy); } +static void +test_connection_no_match_vlan (void) +{ + NMConnection *orig, *copy, *matched; + GSList *connections = NULL; + NMSettingConnection *s_con; + NMSettingVlan *s_vlan_orig, *s_vlan_copy; + char *uuid; + + orig = nm_simple_connection_new (); + s_con = (NMSettingConnection *) nm_setting_connection_new (); + nm_connection_add_setting (orig, (NMSetting *) s_con); + uuid = nm_utils_uuid_generate (); + g_object_set (G_OBJECT (s_con), + NM_SETTING_CONNECTION_ID, "vlan-test", + NM_SETTING_CONNECTION_UUID, uuid, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_VLAN_SETTING_NAME, + NM_SETTING_CONNECTION_AUTOCONNECT, FALSE, + NULL); + g_free (uuid); + nm_connection_add_setting (orig, nm_setting_vlan_new ()); + + copy = nm_simple_connection_new_clone (orig); + connections = g_slist_append (connections, copy); + + /* Check that the connections do not match if VLAN flags differ */ + s_vlan_orig = nm_connection_get_setting_vlan (orig); + g_assert (s_vlan_orig); + g_object_set (G_OBJECT (s_vlan_orig), + NM_SETTING_VLAN_FLAGS, NM_VLAN_FLAG_REORDER_HEADERS, + NULL); + + s_vlan_copy = nm_connection_get_setting_vlan (copy); + g_assert (s_vlan_copy); + g_object_set (G_OBJECT (s_vlan_copy), + NM_SETTING_VLAN_FLAGS, 0, + NULL); + + matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL); + g_assert (matched != copy); + + /* Check that the connections do not match if VLAN priorities differ */ + g_object_set (G_OBJECT (s_vlan_orig), NM_SETTING_VLAN_FLAGS, 0, NULL); + nm_setting_vlan_add_priority_str (s_vlan_orig, NM_VLAN_INGRESS_MAP, "1:3"); + + g_object_set (G_OBJECT (s_vlan_copy), NM_SETTING_VLAN_FLAGS, 0, NULL); + nm_setting_vlan_add_priority_str (s_vlan_copy, NM_VLAN_INGRESS_MAP, "4:2"); + + matched = nm_utils_match_connection (connections, orig, TRUE, NULL, NULL); + g_assert (matched != copy); + + g_slist_free (connections); + g_object_unref (orig); + g_object_unref (copy); +} + static NMConnection * _create_connection_autoconnect (const char *id, gboolean autoconnect, int autoconnect_priority) { @@ -806,6 +861,258 @@ test_nm_match_spec_interface_name (void) /*******************************************/ +static void +_do_test_match_spec_match_config (const char *file, gint line, const char *spec_str, guint version, guint v_maj, guint v_min, guint v_mic, NMMatchSpecMatchType expected) +{ + GSList *specs; + NMMatchSpecMatchType match_result; + guint c_maj, c_min, c_mic; + + g_assert_cmpint (version, ==, nm_encode_version (v_maj, v_min, v_mic)); + + nm_decode_version (version, &c_maj, &c_min, &c_mic); + g_assert_cmpint (c_maj, ==, c_maj); + g_assert_cmpint (c_min, ==, c_min); + g_assert_cmpint (c_mic, ==, c_mic); + + specs = nm_match_spec_split (spec_str); + + match_result = nm_match_spec_match_config (specs, version, NULL); + + if (expected != match_result) + g_error ("%s:%d: faild comparing \"%s\" with %u.%u.%u. Expected %d, but got %d", file, line, spec_str, v_maj, v_min, v_mic, (int) expected, (int) match_result); + + if (g_slist_length (specs) == 1 && match_result != NM_MATCH_SPEC_NEG_MATCH) { + /* there is only one spec in the list... test that we match except: */ + char *sss = g_strdup_printf ("except:%s", (char *) specs->data); + GSList *specs2 = g_slist_append (NULL, sss); + NMMatchSpecMatchType match_result2; + + + match_result2 = nm_match_spec_match_config (specs2, version, NULL); + if (match_result == NM_MATCH_SPEC_NO_MATCH) + g_assert_cmpint (match_result2, ==, NM_MATCH_SPEC_NO_MATCH); + else + g_assert_cmpint (match_result2, ==, NM_MATCH_SPEC_NEG_MATCH); + + g_slist_free_full (specs2, g_free); + } + + g_slist_free_full (specs, g_free); +} +#define do_test_match_spec_match_config(spec, v_maj, v_min, v_mic, expected) \ + _do_test_match_spec_match_config (__FILE__, __LINE__, (""spec), NM_ENCODE_VERSION ((v_maj), (v_min), (v_mic)), (v_maj), (v_min), (v_mic), (expected)) + +static void +test_nm_match_spec_match_config (void) +{ + do_test_match_spec_match_config ("", 1, 2, 3, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version:1.2.3", 1, 2, 2, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version:1.2.3", 1, 2, 3, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version:1.2.3", 1, 2, 4, NM_MATCH_SPEC_NO_MATCH); + + do_test_match_spec_match_config ("nm-version:1.2", 1, 1, 2, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version:1.2", 1, 2, 0, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version:1.2", 1, 2, 2, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version:1.2", 1, 2, 3, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version:1.2", 1, 2, 4, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version:1.2", 1, 3, 0, NM_MATCH_SPEC_NO_MATCH); + + do_test_match_spec_match_config ("nm-version-min:1.2.3", 0, 2, 30, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.2.3", 1, 1, 1, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.2.3", 1, 2, 2, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.2.3", 1, 2, 3, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.2.3", 1, 2, 5, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.2.3", 1, 3, 0, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.2.3", 1, 3, 30, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.2.3", 1, 4, 30, NM_MATCH_SPEC_NO_MATCH); + + do_test_match_spec_match_config ("nm-version-min:1.2", 0, 2, 30, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.2", 1, 1, 1, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.2", 1, 2, 0, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.2", 1, 2, 3, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.2", 1, 2, 5, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.2", 1, 3, 0, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.2", 1, 3, 30, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.2", 1, 4, 30, NM_MATCH_SPEC_MATCH); + + do_test_match_spec_match_config ("nm-version-min:1", 0, 2, 30, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1", 1, 1, 1, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1", 1, 2, 0, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1", 1, 2, 3, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1", 1, 2, 5, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1", 1, 3, 0, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1", 1, 3, 30, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1", 1, 4, 30, NM_MATCH_SPEC_MATCH); + + + do_test_match_spec_match_config ("nm-version-max:1.2.3", 0, 2, 30, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 1, 1, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 2, 0, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 2, 1, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 2, 2, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 2, 3, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 2, 5, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 3, 0, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 3, 30, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2.3", 1, 4, 30, NM_MATCH_SPEC_NO_MATCH); + + do_test_match_spec_match_config ("nm-version-max:1.2", 0, 2, 30, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2", 1, 1, 1, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2", 1, 2, 0, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2", 1, 2, 3, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2", 1, 2, 5, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2", 1, 3, 0, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2", 1, 3, 30, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-max:1.2", 1, 4, 30, NM_MATCH_SPEC_NO_MATCH); + + do_test_match_spec_match_config ("nm-version-max:1", 0, 2, 30, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1", 1, 1, 1, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1", 1, 2, 0, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1", 1, 2, 3, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1", 1, 2, 5, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1", 1, 3, 0, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1", 1, 3, 30, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1", 1, 4, 30, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-max:1", 2, 4, 30, NM_MATCH_SPEC_NO_MATCH); + + do_test_match_spec_match_config ("except:nm-version:1.4.8", 1, 6, 0, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,except:nm-version:1.4.8", 1, 6, 0, NM_MATCH_SPEC_MATCH); + + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 2, 0, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 2, 0, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 2, 15, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 2, 16, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 2, 17, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 2, 20, NM_MATCH_SPEC_MATCH); + + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 3, 0, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 4, 0, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 4, 5, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 4, 6, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 4, 7, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 4, 8, NM_MATCH_SPEC_NEG_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 4, 9, NM_MATCH_SPEC_MATCH); + + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 5, 0, NM_MATCH_SPEC_NO_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 6, 0, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 6, 5, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 7, 7, NM_MATCH_SPEC_MATCH); + do_test_match_spec_match_config ("nm-version-min:1.6,nm-version-min:1.4.6,nm-version-min:1.2.16,except:nm-version:1.4.8", 1, 8, 8, NM_MATCH_SPEC_MATCH); +} + +/*******************************************/ + +static void +test_nm_utils_strbuf_append (void) +{ +#define BUF_ORIG "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define STR_ORIG "abcdefghijklmnopqrstuvwxyz" + int buf_len; + int rep; + char buf[STRLEN (BUF_ORIG) + 1]; + char str[STRLEN (BUF_ORIG) + 1]; + + for (buf_len = 0; buf_len < 10; buf_len++) { + for (rep = 0; rep < 50; rep++) { + const int s_len = nmtst_get_rand_int () % (sizeof (str) - 5); + char *t_buf; + gsize t_len; + int test_mode; + + strcpy (str, STR_ORIG); + str[s_len] = '\0'; + + g_assert_cmpint (str[sizeof (str) - 1], ==, '\0'); + g_assert_cmpint (strlen (str), ==, s_len); + + strcpy (buf, BUF_ORIG); + + t_buf = buf; + t_len = buf_len; + + test_mode = nmtst_get_rand_int () % 4; + + switch (test_mode) { + case 0: + if (s_len == 1) { + nm_utils_strbuf_append_c (&t_buf, &t_len, str[0]); + break; + } + /* fall-through */ + case 1: + nm_utils_strbuf_append_str (&t_buf, &t_len, str); + break; + case 2: + if (s_len == 1) { + nm_utils_strbuf_append (&t_buf, &t_len, "%c", str[0]); + break; + } + /* fall-through */ + case 3: + nm_utils_strbuf_append (&t_buf, &t_len, "%s", str); + break; + } + + /* Assert that the source-buffer is unmodified. */ + g_assert_cmpint (str[s_len], ==, '\0'); + str[s_len] = STR_ORIG[s_len]; + g_assert (!memcmp (str, STR_ORIG, sizeof (str))); + str[s_len] = '\0'; + + g_assert_cmpint (t_len, >=, 0); + g_assert_cmpint (t_len, <=, buf_len); + g_assert (t_buf >= buf); + + /* Assert what was written to the destination buffer. */ + switch (buf_len) { + case 0: + g_assert_cmpint (t_len, ==, 0); + g_assert (t_buf == buf); + g_assert (!memcmp (buf, BUF_ORIG, sizeof (buf))); + break; + case 1: + if (s_len == 0) { + g_assert_cmpint (t_len, ==, 1); + g_assert (t_buf == buf); + g_assert (buf[0] == '\0'); + g_assert (!memcmp (&buf[1], &BUF_ORIG[1], sizeof (buf) - 1)); + } else { + g_assert_cmpint (t_len, ==, 0); + g_assert (t_buf == &buf[1]); + g_assert (buf[0] == '\0'); + g_assert (!memcmp (&buf[1], &BUF_ORIG[1], sizeof (buf) - 1)); + } + break; + default: + if (s_len == 0) { + g_assert_cmpint (t_len, ==, buf_len); + g_assert (t_buf == buf); + g_assert (buf[0] == '\0'); + g_assert (!memcmp (&buf[1], &BUF_ORIG[1], sizeof (buf) - 1)); + } else if (buf_len <= s_len) { + g_assert_cmpint (t_len, ==, 0); + g_assert (t_buf == &buf[buf_len]); + g_assert (!memcmp (buf, STR_ORIG, buf_len - 1)); + g_assert (buf[buf_len - 1] == '\0'); + g_assert (!memcmp (&buf[buf_len], &BUF_ORIG[buf_len], sizeof (buf) - buf_len)); + } else { + g_assert_cmpint (t_len, >, 0); + g_assert_cmpint (buf_len - t_len, ==, s_len); + g_assert_cmpint (strlen (buf), ==, s_len); + g_assert (t_buf == &buf[s_len]); + g_assert (!memcmp (buf, STR_ORIG, s_len)); + g_assert (buf[s_len] == '\0'); + g_assert (!memcmp (&buf[s_len + 1], &BUF_ORIG[s_len + 1], sizeof (buf) - s_len - 1)); + } + break; + } + } + } +} + +/*******************************************/ + NMTST_DEFINE (); int @@ -813,6 +1120,8 @@ main (int argc, char **argv) { nmtst_init_with_logging (&argc, &argv, NULL, "ALL"); + g_test_add_func ("/general/nm_utils_strbuf_append", test_nm_utils_strbuf_append); + g_test_add_func ("/general/nm_utils_ip6_address_clear_host_address", test_nm_utils_ip6_address_clear_host_address); g_test_add_func ("/general/nm_utils_log_connection_diff", test_nm_utils_log_connection_diff); @@ -826,10 +1135,12 @@ main (int argc, char **argv) g_test_add_func ("/general/connection-match/wired2", test_connection_match_wired2); g_test_add_func ("/general/connection-match/cloned_mac", test_connection_match_cloned_mac); g_test_add_func ("/general/connection-match/no-match-ip4-addr", test_connection_no_match_ip4_addr); + g_test_add_func ("/general/connection-match/no-match-vlan", test_connection_no_match_vlan); g_test_add_func ("/general/connection-sort/autoconnect-priority", test_connection_sort_autoconnect_priority); g_test_add_func ("/general/nm_match_spec_interface_name", test_nm_match_spec_interface_name); + g_test_add_func ("/general/nm_match_spec_match_config", test_nm_match_spec_match_config); return g_test_run (); } diff --git a/src/tests/test-ip4-config.c b/src/tests/test-ip4-config.c index 404940d4..16cd3d1e 100644 --- a/src/tests/test-ip4-config.c +++ b/src/tests/test-ip4-config.c @@ -20,13 +20,15 @@ #include "config.h" -#include #include #include +#include "nm-default.h" #include "nm-ip4-config.h" #include "nm-platform.h" +#include "nm-test-utils.h" + static void addr_init (NMPlatformIP4Address *a, const char *addr, const char *peer, guint plen) { @@ -34,6 +36,8 @@ addr_init (NMPlatformIP4Address *a, const char *addr, const char *peer, guint pl g_assert (inet_pton (AF_INET, addr, (void *) &a->address) == 1); if (peer) g_assert (inet_pton (AF_INET, peer, (void *) &a->peer_address) == 1); + else + a->peer_address = a->address; a->plen = plen; } @@ -71,7 +75,7 @@ build_test_config (void) NMPlatformIP4Route route; /* Build up the config to subtract */ - config = nm_ip4_config_new (); + config = nm_ip4_config_new (1); addr_init (&addr, "192.168.1.10", "1.2.3.4", 24); nm_ip4_config_add_address (config, &addr); @@ -150,7 +154,7 @@ test_subtract (void) test_addr = nm_ip4_config_get_address (dst, 0); g_assert (test_addr != NULL); g_assert_cmpuint (test_addr->address, ==, addr_to_num (expected_addr)); - g_assert_cmpuint (test_addr->peer_address, ==, 0); + g_assert_cmpuint (test_addr->peer_address, ==, test_addr->address); g_assert_cmpuint (test_addr->plen, ==, expected_addr_plen); g_assert_cmpuint (nm_ip4_config_get_gateway (dst), ==, 0); @@ -191,8 +195,8 @@ test_compare_with_source (void) NMPlatformIP4Address addr; NMPlatformIP4Route route; - a = nm_ip4_config_new (); - b = nm_ip4_config_new (); + a = nm_ip4_config_new (1); + b = nm_ip4_config_new (2); /* Address */ addr_init (&addr, "1.2.3.4", NULL, 24); @@ -224,7 +228,7 @@ test_add_address_with_source (void) NMPlatformIP4Address addr; const NMPlatformIP4Address *test_addr; - a = nm_ip4_config_new (); + a = nm_ip4_config_new (1); /* Test that a higher priority source is not overwritten */ addr_init (&addr, "1.2.3.4", NULL, 24); @@ -264,7 +268,7 @@ test_add_route_with_source (void) NMPlatformIP4Route route; const NMPlatformIP4Route *test_route; - a = nm_ip4_config_new (); + a = nm_ip4_config_new (1); /* Test that a higher priority source is not overwritten */ route_new (&route, "1.2.3.4", 24, "1.2.3.1"); @@ -341,7 +345,7 @@ test_strip_search_trailing_dot (void) { NMIP4Config *config; - config = nm_ip4_config_new (); + config = nm_ip4_config_new (1); nm_ip4_config_add_search (config, "."); nm_ip4_config_add_search (config, "foo"); @@ -359,14 +363,12 @@ test_strip_search_trailing_dot (void) /*******************************************/ +NMTST_DEFINE (); + int main (int argc, char **argv) { - g_test_init (&argc, &argv, NULL); - -#if !GLIB_CHECK_VERSION (2, 35, 0) - g_type_init (); -#endif + nmtst_init_with_logging (&argc, &argv, NULL, "DEFAULT"); g_test_add_func ("/ip4-config/subtract", test_subtract); g_test_add_func ("/ip4-config/compare-with-source", test_compare_with_source); diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c index a5397b8a..2639a1f0 100644 --- a/src/tests/test-ip6-config.c +++ b/src/tests/test-ip6-config.c @@ -20,13 +20,12 @@ #include "config.h" -#include #include #include +#include "nm-default.h" #include "nm-ip6-config.h" -#include "nm-logging.h" #include "nm-platform.h" #include "nm-test-utils.h" @@ -36,7 +35,7 @@ build_test_config (void) NMIP6Config *config; /* Build up the config to subtract */ - config = nm_ip6_config_new (); + config = nm_ip6_config_new (1); nm_ip6_config_add_address (config, nmtst_platform_ip6_address ("abcd:1234:4321::cdde", "1:2:3:4::5", 64)); nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2")); @@ -129,8 +128,8 @@ test_compare_with_source (void) NMPlatformIP6Address addr; NMPlatformIP6Route route; - a = nm_ip6_config_new (); - b = nm_ip6_config_new (); + a = nm_ip6_config_new (1); + b = nm_ip6_config_new (2); /* Address */ addr = *nmtst_platform_ip6_address ("1122:3344:5566::7788", NULL, 64); @@ -162,7 +161,7 @@ test_add_address_with_source (void) NMPlatformIP6Address addr; const NMPlatformIP6Address *test_addr; - a = nm_ip6_config_new (); + a = nm_ip6_config_new (1); /* Test that a higher priority source is not overwritten */ addr = *nmtst_platform_ip6_address ("1122:3344:5566::7788", NULL, 64); @@ -202,7 +201,7 @@ test_add_route_with_source (void) NMPlatformIP6Route route; const NMPlatformIP6Route *test_route; - a = nm_ip6_config_new (); + a = nm_ip6_config_new (1); /* Test that a higher priority source is not overwritten */ route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2"); @@ -265,8 +264,8 @@ test_nm_ip6_config_addresses_sort_check (NMIP6Config *config, NMSettingIP6Config if (!nm_ip6_config_equal (copy, config)) { g_message ("%s", "SORTING yields unexpected output:"); for (i = 0; i < addr_count; i++) { - g_message (" >> [%d] = %s", i, nm_platform_ip6_address_to_string (nm_ip6_config_get_address (config, i))); - g_message (" << [%d] = %s", i, nm_platform_ip6_address_to_string (nm_ip6_config_get_address (copy, i))); + g_message (" >> [%d] = %s", i, nm_platform_ip6_address_to_string (nm_ip6_config_get_address (config, i), NULL, 0)); + g_message (" << [%d] = %s", i, nm_platform_ip6_address_to_string (nm_ip6_config_get_address (copy, i), NULL, 0)); } g_assert_not_reached (); } @@ -326,7 +325,7 @@ test_strip_search_trailing_dot (void) { NMIP6Config *config; - config = nm_ip6_config_new (); + config = nm_ip6_config_new (1); nm_ip6_config_add_search (config, "."); nm_ip6_config_add_search (config, "foo"); diff --git a/src/tests/test-resolvconf-capture.c b/src/tests/test-resolvconf-capture.c index f5cb298b..db7006ba 100644 --- a/src/tests/test-resolvconf-capture.c +++ b/src/tests/test-resolvconf-capture.c @@ -20,25 +20,27 @@ #include "config.h" -#include #include #include +#include "nm-default.h" #include "NetworkManagerUtils.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" #include "nm-platform.h" +#include "nm-test-utils.h" + static void test_capture_empty (void) { GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32)); GArray *ns6 = g_array_new (FALSE, FALSE, sizeof (struct in6_addr)); - g_assert (nm_ip4_config_capture_resolv_conf (ns4, "") == FALSE); + g_assert (nm_ip4_config_capture_resolv_conf (ns4, NULL, "") == FALSE); g_assert_cmpint (ns4->len, ==, 0); - g_assert (nm_ip6_config_capture_resolv_conf (ns6, "") == FALSE); + g_assert (nm_ip6_config_capture_resolv_conf (ns6, NULL, "") == FALSE); g_assert_cmpint (ns6->len, ==, 0); g_array_free (ns4, TRUE); @@ -66,6 +68,12 @@ assert_dns6_entry (const GArray *a, guint i, const char *s) g_assert (IN6_ARE_ADDR_EQUAL (&n, m)); } +static void +assert_dns_option (GPtrArray *a, guint i, const char *s) +{ + g_assert_cmpstr (a->pdata[i], ==, s); +} + static void test_capture_basic4 (void) { @@ -77,7 +85,7 @@ test_capture_basic4 (void) "nameserver 4.2.2.1\r\n" "nameserver 4.2.2.2\r\n"; - g_assert (nm_ip4_config_capture_resolv_conf (ns4, rc)); + g_assert (nm_ip4_config_capture_resolv_conf (ns4, NULL, rc)); g_assert_cmpint (ns4->len, ==, 2); assert_dns4_entry (ns4, 0, "4.2.2.1"); assert_dns4_entry (ns4, 1, "4.2.2.2"); @@ -98,7 +106,7 @@ test_capture_dup4 (void) "nameserver 4.2.2.2\r\n"; /* Check that duplicates are ignored */ - g_assert (nm_ip4_config_capture_resolv_conf (ns4, rc)); + g_assert (nm_ip4_config_capture_resolv_conf (ns4, NULL, rc)); g_assert_cmpint (ns4->len, ==, 2); assert_dns4_entry (ns4, 0, "4.2.2.1"); assert_dns4_entry (ns4, 1, "4.2.2.2"); @@ -117,7 +125,7 @@ test_capture_basic6 (void) "nameserver 2001:4860:4860::8888\r\n" "nameserver 2001:4860:4860::8844\r\n"; - g_assert (nm_ip6_config_capture_resolv_conf (ns6, rc)); + g_assert (nm_ip6_config_capture_resolv_conf (ns6, NULL, rc)); g_assert_cmpint (ns6->len, ==, 2); assert_dns6_entry (ns6, 0, "2001:4860:4860::8888"); assert_dns6_entry (ns6, 1, "2001:4860:4860::8844"); @@ -138,7 +146,7 @@ test_capture_dup6 (void) "nameserver 2001:4860:4860::8844\r\n"; /* Check that duplicates are ignored */ - g_assert (nm_ip6_config_capture_resolv_conf (ns6, rc)); + g_assert (nm_ip6_config_capture_resolv_conf (ns6, NULL, rc)); g_assert_cmpint (ns6->len, ==, 2); assert_dns6_entry (ns6, 0, "2001:4860:4860::8888"); assert_dns6_entry (ns6, 1, "2001:4860:4860::8844"); @@ -158,7 +166,7 @@ test_capture_addr4_with_6 (void) "nameserver 4.2.2.2\r\n" "nameserver 2001:4860:4860::8888\r\n"; - g_assert (nm_ip4_config_capture_resolv_conf (ns4, rc)); + g_assert (nm_ip4_config_capture_resolv_conf (ns4, NULL, rc)); g_assert_cmpint (ns4->len, ==, 2); assert_dns4_entry (ns4, 0, "4.2.2.1"); assert_dns4_entry (ns4, 1, "4.2.2.2"); @@ -178,7 +186,7 @@ test_capture_addr6_with_4 (void) "nameserver 2001:4860:4860::8888\r\n" "nameserver 2001:4860:4860::8844\r\n"; - g_assert (nm_ip6_config_capture_resolv_conf (ns6, rc)); + g_assert (nm_ip6_config_capture_resolv_conf (ns6, NULL, rc)); g_assert_cmpint (ns6->len, ==, 2); assert_dns6_entry (ns6, 0, "2001:4860:4860::8888"); assert_dns6_entry (ns6, 1, "2001:4860:4860::8844"); @@ -197,7 +205,7 @@ test_capture_format (void) "nameserver\t\t4.2.2.4\r\n" /* good */ "nameserver 4.2.2.5\t\t\r\n"; /* good */ - g_assert (nm_ip4_config_capture_resolv_conf (ns4, rc)); + g_assert (nm_ip4_config_capture_resolv_conf (ns4, NULL, rc)); g_assert_cmpint (ns4->len, ==, 3); assert_dns4_entry (ns4, 0, "4.2.2.3"); assert_dns4_entry (ns4, 1, "4.2.2.4"); @@ -206,16 +214,88 @@ test_capture_format (void) g_array_free (ns4, TRUE); } +static void +test_capture_dns_options (void) +{ + GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32)); + GPtrArray *dns_options = g_ptr_array_new_with_free_func (g_free); + const char *rc = +"nameserver 4.2.2.1\r\n" +"options debug rotate timeout:5 \r\n" +"options edns0\r\n"; + + g_assert (nm_ip4_config_capture_resolv_conf (ns4, dns_options, rc)); + g_assert_cmpint (dns_options->len, ==, 4); + assert_dns_option (dns_options, 0, "debug"); + assert_dns_option (dns_options, 1, "rotate"); + assert_dns_option (dns_options, 2, "timeout:5"); + assert_dns_option (dns_options, 3, "edns0"); + + g_array_free (ns4, TRUE); + g_ptr_array_free (dns_options, TRUE); +} + +static void +test_capture_dns_options_dup (void) +{ + GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32)); + GPtrArray *dns_options = g_ptr_array_new_with_free_func (g_free); + const char *rc = +"options debug rotate timeout:3\r\n" +"options edns0 debug\r\n" +"options timeout:5\r\n"; + + g_assert (nm_ip4_config_capture_resolv_conf (ns4, dns_options, rc)); + g_assert_cmpint (dns_options->len, ==, 4); + assert_dns_option (dns_options, 0, "debug"); + assert_dns_option (dns_options, 1, "rotate"); + assert_dns_option (dns_options, 2, "timeout:3"); + assert_dns_option (dns_options, 3, "edns0"); + + g_array_free (ns4, TRUE); + g_ptr_array_free (dns_options, TRUE); +} + +static void +test_capture_dns_options_valid4 (void) +{ + GArray *ns4 = g_array_new (FALSE, FALSE, sizeof (guint32)); + GPtrArray *dns_options = g_ptr_array_new_with_free_func (g_free); + const char *rc = +"options debug: rotate:yes edns0 foobar : inet6\r\n"; + + g_assert (nm_ip4_config_capture_resolv_conf (ns4, dns_options, rc)); + g_assert_cmpint (dns_options->len, ==, 1); + assert_dns_option (dns_options, 0, "edns0"); + + g_array_free (ns4, TRUE); + g_ptr_array_free (dns_options, TRUE); +} + +static void +test_capture_dns_options_valid6 (void) +{ + GArray *ns6 = g_array_new (FALSE, FALSE, sizeof (guint32)); + GPtrArray *dns_options = g_ptr_array_new_with_free_func (g_free); + const char *rc = +"options inet6 debug foobar rotate:\r\n"; + + g_assert (nm_ip6_config_capture_resolv_conf (ns6, dns_options, rc)); + g_assert_cmpint (dns_options->len, ==, 2); + assert_dns_option (dns_options, 0, "inet6"); + assert_dns_option (dns_options, 1, "debug"); + + g_array_free (ns6, TRUE); + g_ptr_array_free (dns_options, TRUE); +} /*******************************************/ +NMTST_DEFINE (); + int main (int argc, char **argv) { - g_test_init (&argc, &argv, NULL); - -#if !GLIB_CHECK_VERSION (2,35,0) - g_type_init (); -#endif + nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); g_test_add_func ("/resolvconf-capture/empty", test_capture_empty); g_test_add_func ("/resolvconf-capture/basic4", test_capture_basic4); @@ -225,6 +305,10 @@ main (int argc, char **argv) g_test_add_func ("/resolvconf-capture/addr4-with-6", test_capture_addr4_with_6); g_test_add_func ("/resolvconf-capture/addr6-with-4", test_capture_addr6_with_4); g_test_add_func ("/resolvconf-capture/format", test_capture_format); + g_test_add_func ("/resolvconf-capture/dns-options", test_capture_dns_options); + g_test_add_func ("/resolvconf-capture/dns-options-dup", test_capture_dns_options_dup); + g_test_add_func ("/resolvconf-capture/dns-options-valid4", test_capture_dns_options_valid4); + g_test_add_func ("/resolvconf-capture/dns-options-valid6", test_capture_dns_options_valid6); return g_test_run (); } diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c index 9046bf88..347c122c 100644 --- a/src/tests/test-route-manager.c +++ b/src/tests/test-route-manager.c @@ -20,15 +20,14 @@ #include "config.h" -#include #include #include +#include "nm-default.h" #include "test-common.h" #include "nm-platform.h" #include "nm-route-manager.h" -#include "nm-logging.h" #include "nm-test-utils.h" @@ -378,8 +377,8 @@ setup_dev0_ip6 (int ifindex) nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, *nmtst_inet6_from_string ("2001:db8:8086::666"), - in6addr_any, 64, + in6addr_any, 3600, 3600, 0); @@ -482,8 +481,8 @@ update_dev0_ip6 (int ifindex) nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, *nmtst_inet6_from_string ("2001:db8:8086::2"), - in6addr_any, 64, + in6addr_any, 3600, 3600, 0); @@ -798,10 +797,12 @@ _assert_route_check (const NMPlatformVTableRoute *vtable, gboolean has, const NM if (!has) { g_assert (!r); } else { + char buf[sizeof (_nm_utils_to_string_buffer)]; + if (!r || vtable->route_cmp (route, r) != 0) g_error ("Invalid route. Expect %s, has %s", - nmtst_static_1024_01 (vtable->route_to_string (route)), - nmtst_static_1024_02 (vtable->route_to_string (r))); + vtable->route_to_string (route, NULL, 0), + vtable->route_to_string (r, buf, sizeof (buf))); g_assert (r); } } @@ -874,7 +875,8 @@ fixture_setup (test_fixture *fixture, gconstpointer user_data) link_callback, "nm-test-device0"); nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device0")); - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device0", NULL) == NM_PLATFORM_ERROR_SUCCESS); + g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "nm-test-device0")); + g_assert (nm_platform_link_dummy_add (NM_PLATFORM_GET, "nm-test-device0", NULL) == NM_PLATFORM_ERROR_SUCCESS); accept_signal (link_added); free_signal (link_added); fixture->ifindex0 = nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device0"); @@ -885,7 +887,8 @@ fixture_setup (test_fixture *fixture, gconstpointer user_data) link_callback, "nm-test-device1"); nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device1")); - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device1", NULL) == NM_PLATFORM_ERROR_SUCCESS); + g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "nm-test-device1")); + g_assert (nm_platform_link_dummy_add (NM_PLATFORM_GET, "nm-test-device1", NULL) == NM_PLATFORM_ERROR_SUCCESS); accept_signal (link_added); free_signal (link_added); fixture->ifindex1 = nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device1"); diff --git a/src/tests/test-utils.c b/src/tests/test-utils.c new file mode 100644 index 00000000..79a7e680 --- /dev/null +++ b/src/tests/test-utils.c @@ -0,0 +1,63 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * 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) 2015 Red Hat, Inc. + * + */ + +#include "config.h" + +#include +#include +#include + +#include "NetworkManagerUtils.c" + +#include "nm-test-utils.h" + +static void +test_stable_privacy (void) +{ + struct in6_addr addr1; + + inet_pton (AF_INET6, "1234::", &addr1); + _set_stable_privacy (&addr1, "eth666", "6b138152-9f3e-4b97-aaf7-e6e553f2a24e", 0, "key", 3, NULL); + nmtst_assert_ip6_address (&addr1, "1234::4ceb:14cd:3d54:793f"); + + /* We get an address without the UUID. */ + inet_pton (AF_INET6, "1::", &addr1); + _set_stable_privacy (&addr1, "eth666", NULL, 384, "key", 3, NULL); + nmtst_assert_ip6_address (&addr1, "1::11aa:2530:9144:dafa"); + + /* We get a different address in a different network. */ + inet_pton (AF_INET6, "2::", &addr1); + _set_stable_privacy (&addr1, "eth666", NULL, 384, "key", 3, NULL); + nmtst_assert_ip6_address (&addr1, "2::338e:8d:c11:8726"); +} + +/*******************************************/ + +NMTST_DEFINE (); + +int +main (int argc, char **argv) +{ + nmtst_init_with_logging (&argc, &argv, NULL, "ALL"); + + g_test_add_func ("/utils/stable_privacy", test_stable_privacy); + + return g_test_run (); +} diff --git a/src/tests/test-wired-defname.c b/src/tests/test-wired-defname.c index b2933de0..989345d8 100644 --- a/src/tests/test-wired-defname.c +++ b/src/tests/test-wired-defname.c @@ -20,13 +20,13 @@ #include "config.h" -#include -#include #include #include +#include "nm-default.h" #include "nm-device-ethernet-utils.h" -#include "gsystem-local-alloc.h" + +#include "nm-test-utils.h" static NMConnection * _new_connection (const char *id) @@ -112,14 +112,12 @@ test_defname_multiple_conflicts (void) /*******************************************/ +NMTST_DEFINE (); + int main (int argc, char **argv) { -#if !GLIB_CHECK_VERSION (2, 35, 0) - g_type_init (); -#endif - - g_test_init (&argc, &argv, NULL); + nmtst_init_assert_logging (&argc, &argv, "INFO", "DEFAULT"); g_test_add_func ("/defname/no_connections", test_defname_no_connections); g_test_add_func ("/defname/no_conflict", test_defname_no_conflict); diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c index 64e5e2ab..c548c9fa 100644 --- a/src/vpn-manager/nm-vpn-connection.c +++ b/src/vpn-manager/nm-vpn-connection.c @@ -21,7 +21,6 @@ #include "config.h" -#include #include #include #include @@ -29,16 +28,13 @@ #include #include +#include "nm-default.h" #include "nm-vpn-connection.h" #include "nm-ip4-config.h" #include "nm-ip6-config.h" -#include "nm-dbus-manager.h" #include "nm-platform.h" -#include "nm-logging.h" #include "nm-active-connection.h" -#include "nm-dbus-glib-types.h" #include "NetworkManagerUtils.h" -#include "nm-glib-compat.h" #include "settings/nm-settings-connection.h" #include "nm-dispatcher.h" #include "nm-agent-manager.h" @@ -46,8 +42,11 @@ #include "nm-default-route-manager.h" #include "nm-route-manager.h" #include "nm-firewall-manager.h" +#include "nm-config.h" +#include "nm-vpn-plugin-info.h" +#include "nm-vpn-manager.h" -#include "nm-vpn-connection-glue.h" +#include "nmdbus-vpn-connection.h" G_DEFINE_TYPE (NMVpnConnection, nm_vpn_connection, NM_TYPE_ACTIVE_CONNECTION) @@ -80,11 +79,10 @@ typedef enum { } VpnState; typedef struct { - NMConnection *connection; gboolean service_can_persist; gboolean connection_can_persist; - guint32 secrets_id; + NMSettingsConnectionCallId secrets_id; SecretsReq secrets_idx; char *username; @@ -93,12 +91,19 @@ typedef struct { NMVpnConnectionStateReason failure_reason; NMVpnServiceState service_state; + guint start_timeout; + gboolean service_running; + NMVpnPluginInfo *plugin_info; + char *bus_name; /* Firewall */ - NMFirewallPendingCall fw_call; + NMFirewallManagerCallId fw_call; - DBusGProxy *proxy; - GHashTable *connect_hash; + NMDefaultRouteManager *default_route_manager; + NMRouteManager *route_manager; + GDBusProxy *proxy; + GCancellable *cancellable; + GVariant *connect_hash; guint connect_timeout; gboolean has_ip4; NMIP4Config *ip4_config; @@ -106,6 +111,13 @@ typedef struct { guint32 ip4_external_gw; gboolean has_ip6; NMIP6Config *ip6_config; + + /* These config instances are passed on to NMDevice and modified by NMDevice. + * This pointer is only useful for nm_device_replace_vpn4_config() to clear the + * previous configuration. Consider these instances to be owned by NMDevice. */ + NMIP4Config *last_device_ip4_config; + NMIP6Config *last_device_ip6_config; + struct in6_addr *ip6_internal_gw; struct in6_addr *ip6_external_gw; char *ip_iface; @@ -137,22 +149,92 @@ enum { LAST_PROP }; +static NMSettingsConnection *_get_settings_connection (NMVpnConnection *self, + gboolean allow_missing); + static void get_secrets (NMVpnConnection *self, SecretsReq secrets_idx, const char **hints); -static void plugin_interactive_secrets_required (DBusGProxy *proxy, +static void plugin_interactive_secrets_required (NMVpnConnection *self, const char *message, - const char **secrets, - gpointer user_data); + const char **secrets); -static void _set_vpn_state (NMVpnConnection *connection, +static void _set_vpn_state (NMVpnConnection *self, VpnState vpn_state, NMVpnConnectionStateReason reason, gboolean quitting); /*********************************************************************/ +#define _NMLOG_DOMAIN LOGD_VPN +#define _NMLOG_PREFIX_NAME "vpn-connection" + +#define __NMLOG_prefix_buf_len 128 + +static const char * +__LOG_create_prefix (char *buf, NMVpnConnection *self) +{ + NMVpnConnectionPrivate *priv; + NMConnection *con; + const char *id; + + if (!self) + return _NMLOG_PREFIX_NAME; + + priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + + con = NM_CONNECTION (_get_settings_connection (self, TRUE)); + id = con ? nm_connection_get_id (con) : NULL; + + g_snprintf (buf, __NMLOG_prefix_buf_len, + "%s[" + "%p" /*self*/ + "%s%s" /*con-uuid*/ + "%s%s%s%s" /*con-id*/ + ",%d" /*ifindex*/ + "%s%s%s%s" /*iface*/ + "]", + _NMLOG_PREFIX_NAME, + self, + con ? "," : "--", con ? str_if_set (nm_connection_get_uuid (con), "??") : "", + con ? "," : "", NM_PRINT_FMT_QUOTED (id, "\"", id, "\"", con ? "??" : ""), + priv->ip_ifindex, + priv->ip_iface ? ":" : "", NM_PRINT_FMT_QUOTED (priv->ip_iface, "(", priv->ip_iface, ")", "") + ); + + return buf; +} + +#define _NMLOG(level, ...) \ + G_STMT_START { \ + const NMLogLevel __level = (level); \ + \ + if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \ + char __prefix[__NMLOG_prefix_buf_len]; \ + \ + _nm_log (__level, _NMLOG_DOMAIN, 0, \ + "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + __LOG_create_prefix (__prefix, self) \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } \ + } G_STMT_END + +/*********************************************************************/ + +static void +cancel_get_secrets (NMVpnConnection *self) +{ + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + + if (priv->secrets_id) { + nm_settings_connection_cancel_secrets (_get_settings_connection (self, FALSE), + priv->secrets_id); + g_warn_if_fail (!priv->secrets_id); + priv->secrets_id = NULL; + } +} + static NMVpnConnectionState _state_to_nm_vpn_state (VpnState state) { @@ -212,57 +294,93 @@ _state_to_ac_state (VpnState vpn_state) return NM_ACTIVE_CONNECTION_STATE_UNKNOWN; } +static NMSettingsConnection * +_get_settings_connection (NMVpnConnection *self, gboolean allow_missing) +{ + NMSettingsConnection *con; + + /* Currently we operate on the assumption, that the settings-connection + * never changes after it is set (though initially, it might be unset). + * Later we might want to change that, but then we need fixes here too. */ + + con = _nm_active_connection_get_settings_connection (NM_ACTIVE_CONNECTION (self)); + if (!con && !allow_missing) + g_return_val_if_reached (NULL); + return con; +} + +static NMConnection * +_get_applied_connection (NMVpnConnection *connection) +{ + NMConnection *con; + + con = nm_active_connection_get_applied_connection (NM_ACTIVE_CONNECTION (connection)); + g_return_val_if_fail (con, NULL); + return con; +} + static void call_plugin_disconnect (NMVpnConnection *self) { NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - GError *error = NULL; if (priv->proxy) { - if (!dbus_g_proxy_call (priv->proxy, "Disconnect", &error, - G_TYPE_INVALID, - G_TYPE_INVALID)) { - nm_log_warn (LOGD_VPN, "error disconnecting VPN: %s", error->message); - g_error_free (error); - } - - g_object_unref (priv->proxy); - priv->proxy = NULL; + g_dbus_proxy_call (priv->proxy, "Disconnect", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); + g_clear_object (&priv->proxy); } } static void -fw_call_cleanup (NMVpnConnection *connection) +fw_call_cleanup (NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); if (priv->fw_call) { - nm_firewall_manager_cancel_call (nm_firewall_manager_get (), priv->fw_call); + nm_firewall_manager_cancel_call (priv->fw_call); + g_warn_if_fail (!priv->fw_call); priv->fw_call = NULL; } } static void -vpn_cleanup (NMVpnConnection *connection, NMDevice *parent_dev) +remove_parent_device_config (NMVpnConnection *connection, NMDevice *device) { NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + if (priv->last_device_ip4_config) { + nm_device_replace_vpn4_config (device, priv->last_device_ip4_config, NULL); + g_clear_object (&priv->last_device_ip4_config); + } + + if (priv->last_device_ip6_config) { + nm_device_replace_vpn6_config (device, priv->last_device_ip6_config, NULL); + g_clear_object (&priv->last_device_ip6_config); + } +} + +static void +vpn_cleanup (NMVpnConnection *self, NMDevice *parent_dev) +{ + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + if (priv->ip_ifindex) { nm_platform_link_set_down (NM_PLATFORM_GET, priv->ip_ifindex); - nm_route_manager_route_flush (nm_route_manager_get (), priv->ip_ifindex); + nm_route_manager_route_flush (priv->route_manager, priv->ip_ifindex); nm_platform_address_flush (NM_PLATFORM_GET, priv->ip_ifindex); } - nm_device_set_vpn4_config (parent_dev, NULL); - nm_device_set_vpn6_config (parent_dev, NULL); + remove_parent_device_config (self, parent_dev); /* Remove zone from firewall */ - if (priv->ip_iface) + if (priv->ip_iface) { nm_firewall_manager_remove_from_zone (nm_firewall_manager_get (), priv->ip_iface, + NULL, + NULL, NULL); + } /* Cancel pending firewall call */ - fw_call_cleanup (connection); + fw_call_cleanup (self); g_free (priv->banner); priv->banner = NULL; @@ -271,12 +389,13 @@ vpn_cleanup (NMVpnConnection *connection, NMDevice *parent_dev) priv->ip_iface = NULL; priv->ip_ifindex = 0; + g_free (priv->bus_name); + priv->bus_name = NULL; + /* Clear out connection secrets to ensure that the settings service * gets asked for them next time the connection is activated. */ - if (priv->connection) - nm_connection_clear_secrets (priv->connection); - + nm_active_connection_clear_secrets (NM_ACTIVE_CONNECTION (self)); } static void @@ -311,7 +430,7 @@ dispatcher_cleanup (NMVpnConnection *self) } static void -_set_vpn_state (NMVpnConnection *connection, +_set_vpn_state (NMVpnConnection *self, VpnState vpn_state, NMVpnConnectionStateReason reason, gboolean quitting) @@ -319,11 +438,11 @@ _set_vpn_state (NMVpnConnection *connection, NMVpnConnectionPrivate *priv; VpnState old_vpn_state; NMVpnConnectionState new_external_state, old_external_state; - NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (connection)); + NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (self)); - g_return_if_fail (NM_IS_VPN_CONNECTION (connection)); + g_return_if_fail (NM_IS_VPN_CONNECTION (self)); - priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + priv = NM_VPN_CONNECTION_GET_PRIVATE (self); if (vpn_state == priv->vpn_state) return; @@ -338,35 +457,32 @@ _set_vpn_state (NMVpnConnection *connection, g_object_ref (parent_dev); /* Update active connection base class state */ - nm_active_connection_set_state (NM_ACTIVE_CONNECTION (connection), + nm_active_connection_set_state (NM_ACTIVE_CONNECTION (self), _state_to_ac_state (vpn_state)); /* Clear any in-progress secrets request */ - if (priv->secrets_id) { - nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), priv->secrets_id); - priv->secrets_id = 0; - } + cancel_get_secrets (self); - dispatcher_cleanup (connection); + dispatcher_cleanup (self); - nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), connection); - nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), connection); + nm_default_route_manager_ip4_update_default_route (priv->default_route_manager, self); + nm_default_route_manager_ip6_update_default_route (priv->default_route_manager, self); /* The connection gets destroyed by the VPN manager when it enters the * disconnected/failed state, but we need to keep it around for a bit * to send out signals and handle the dispatcher. So ref it. */ - g_object_ref (connection); + g_object_ref (self); old_external_state = _state_to_nm_vpn_state (old_vpn_state); new_external_state = _state_to_nm_vpn_state (priv->vpn_state); if (new_external_state != old_external_state) { - g_signal_emit (connection, signals[VPN_STATE_CHANGED], 0, new_external_state, reason); - g_signal_emit (connection, signals[INTERNAL_STATE_CHANGED], 0, + g_signal_emit (self, signals[VPN_STATE_CHANGED], 0, new_external_state, reason); + g_signal_emit (self, signals[INTERNAL_STATE_CHANGED], 0, new_external_state, old_external_state, reason); - g_object_notify (G_OBJECT (connection), NM_VPN_CONNECTION_VPN_STATE); + g_object_notify (G_OBJECT (self), NM_VPN_CONNECTION_VPN_STATE); } switch (vpn_state) { @@ -378,25 +494,27 @@ _set_vpn_state (NMVpnConnection *connection, break; case STATE_PRE_UP: if (!nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_PRE_UP, - priv->connection, + _get_settings_connection (self, FALSE), + _get_applied_connection (self), parent_dev, priv->ip_iface, priv->ip4_config, priv->ip6_config, dispatcher_pre_up_done, - connection, + self, &priv->dispatcher_id)) { /* Just proceed on errors */ - dispatcher_pre_up_done (0, connection); + dispatcher_pre_up_done (0, self); } break; case STATE_ACTIVATED: /* Secrets no longer needed now that we're connected */ - nm_connection_clear_secrets (priv->connection); + nm_active_connection_clear_secrets (NM_ACTIVE_CONNECTION (self)); /* Let dispatcher scripts know we're up and running */ nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_UP, - priv->connection, + _get_settings_connection (self, FALSE), + _get_applied_connection (self), parent_dev, priv->ip_iface, priv->ip4_config, @@ -408,23 +526,25 @@ _set_vpn_state (NMVpnConnection *connection, case STATE_DEACTIVATING: if (quitting) { nm_dispatcher_call_vpn_sync (DISPATCHER_ACTION_VPN_PRE_DOWN, - priv->connection, + _get_settings_connection (self, FALSE), + _get_applied_connection (self), parent_dev, priv->ip_iface, priv->ip4_config, priv->ip6_config); } else { if (!nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_PRE_DOWN, - priv->connection, + _get_settings_connection (self, FALSE), + _get_applied_connection (self), parent_dev, priv->ip_iface, priv->ip4_config, priv->ip6_config, dispatcher_pre_down_done, - connection, + self, &priv->dispatcher_id)) { /* Just proceed on errors */ - dispatcher_pre_down_done (0, connection); + dispatcher_pre_down_done (0, self); } } break; @@ -435,14 +555,16 @@ _set_vpn_state (NMVpnConnection *connection, /* Let dispatcher scripts know we're about to go down */ if (quitting) { nm_dispatcher_call_vpn_sync (DISPATCHER_ACTION_VPN_DOWN, - priv->connection, + _get_settings_connection (self, FALSE), + _get_applied_connection (self), parent_dev, priv->ip_iface, NULL, NULL); } else { nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_DOWN, - priv->connection, + _get_settings_connection (self, FALSE), + _get_applied_connection (self), parent_dev, priv->ip_iface, NULL, @@ -454,15 +576,15 @@ _set_vpn_state (NMVpnConnection *connection, } /* Tear down and clean up the connection */ - call_plugin_disconnect (connection); - vpn_cleanup (connection, parent_dev); + call_plugin_disconnect (self); + vpn_cleanup (self, parent_dev); /* Fall through */ default: priv->secrets_idx = SECRETS_REQ_SYSTEM; break; } - g_object_unref (connection); + g_object_unref (self); if (parent_dev) g_object_unref (parent_dev); } @@ -619,16 +741,16 @@ add_ip6_vpn_gateway_route (NMIP6Config *config, } NMVpnConnection * -nm_vpn_connection_new (NMConnection *connection, +nm_vpn_connection_new (NMSettingsConnection *settings_connection, NMDevice *parent_device, const char *specific_object, NMAuthSubject *subject) { - g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL); g_return_val_if_fail (NM_IS_DEVICE (parent_device), NULL); return (NMVpnConnection *) g_object_new (NM_TYPE_VPN_CONNECTION, - NM_ACTIVE_CONNECTION_INT_CONNECTION, connection, + NM_ACTIVE_CONNECTION_INT_SETTINGS_CONNECTION, settings_connection, NM_ACTIVE_CONNECTION_INT_DEVICE, parent_device, NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object, NM_ACTIVE_CONNECTION_INT_SUBJECT, subject, @@ -636,13 +758,12 @@ nm_vpn_connection_new (NMConnection *connection, NULL); } -static const char * -nm_vpn_connection_get_service (NMVpnConnection *connection) +const char * +nm_vpn_connection_get_service (NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); NMSettingVpn *s_vpn; - s_vpn = nm_connection_get_setting_vpn (priv->connection); + s_vpn = nm_connection_get_setting_vpn (_get_applied_connection (self)); return nm_setting_vpn_get_service_type (s_vpn); } @@ -663,16 +784,13 @@ vpn_plugin_failure_to_string (NMVpnPluginFailure failure) } static void -plugin_failed (DBusGProxy *proxy, - NMVpnPluginFailure plugin_failure, - gpointer user_data) +plugin_failed (NMVpnConnection *self, guint reason) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (user_data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - nm_log_warn (LOGD_VPN, "VPN plugin failed: %s (%d)", - vpn_plugin_failure_to_string (plugin_failure), plugin_failure); + _LOGW ("VPN plugin: failed: %s (%d)", vpn_plugin_failure_to_string (reason), reason); - switch (plugin_failure) { + switch (reason) { case NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED: priv->failure_reason = NM_VPN_CONNECTION_STATE_REASON_LOGIN_FAILED; break; @@ -762,30 +880,27 @@ vpn_reason_to_string (NMVpnConnectionStateReason reason) } static void -plugin_state_changed (DBusGProxy *proxy, - NMVpnServiceState new_service_state, - gpointer user_data) +plugin_state_changed (NMVpnConnection *self, NMVpnServiceState new_service_state) { - NMVpnConnection *connection = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); NMVpnServiceState old_service_state = priv->service_state; - nm_log_info (LOGD_VPN, "VPN plugin state changed: %s (%d)", - vpn_service_state_to_string (new_service_state), new_service_state); + _LOGI ("VPN plugin: state changed: %s (%d)", + vpn_service_state_to_string (new_service_state), new_service_state); priv->service_state = new_service_state; if (new_service_state == NM_VPN_SERVICE_STATE_STOPPED) { /* Clear connection secrets to ensure secrets get requested each time the * connection is activated. */ - nm_connection_clear_secrets (priv->connection); + nm_active_connection_clear_secrets (NM_ACTIVE_CONNECTION (self)); if ((priv->vpn_state >= STATE_WAITING) && (priv->vpn_state <= STATE_ACTIVATED)) { VpnState old_state = priv->vpn_state; - nm_log_info (LOGD_VPN, "VPN plugin state change reason: %s (%d)", - vpn_reason_to_string (priv->failure_reason), priv->failure_reason); - _set_vpn_state (connection, STATE_FAILED, priv->failure_reason, FALSE); + _LOGI ("VPN plugin: state change reason: %s (%d)", + vpn_reason_to_string (priv->failure_reason), priv->failure_reason); + _set_vpn_state (self, STATE_FAILED, priv->failure_reason, FALSE); /* Reset the failure reason */ priv->failure_reason = NM_VPN_CONNECTION_STATE_REASON_UNKNOWN; @@ -795,20 +910,20 @@ plugin_state_changed (DBusGProxy *proxy, */ if ( old_state == STATE_ACTIVATED && priv->vpn_state == STATE_FAILED - && _connection_only_can_persist (connection)) - g_signal_emit (connection, signals[INTERNAL_RETRY_AFTER_FAILURE], 0); + && _connection_only_can_persist (self)) + g_signal_emit (self, signals[INTERNAL_RETRY_AFTER_FAILURE], 0); } } else if (new_service_state == NM_VPN_SERVICE_STATE_STARTING && old_service_state == NM_VPN_SERVICE_STATE_STARTED) { /* The VPN service got disconnected and is attempting to reconnect */ - _set_vpn_state (connection, STATE_CONNECT, NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, FALSE); + _set_vpn_state (self, STATE_CONNECT, NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, FALSE); } } static void -print_vpn_config (NMVpnConnection *connection) +print_vpn_config (NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); const NMPlatformIP4Address *address4; const NMPlatformIP6Address *address6; char *dns_domain = NULL; @@ -816,113 +931,115 @@ print_vpn_config (NMVpnConnection *connection) char buf[NM_UTILS_INET_ADDRSTRLEN]; if (priv->ip4_external_gw) { - nm_log_info (LOGD_VPN, "VPN Gateway: %s", - nm_utils_inet4_ntop (priv->ip4_external_gw, NULL)); + _LOGI ("Data: VPN Gateway: %s", + nm_utils_inet4_ntop (priv->ip4_external_gw, NULL)); } else if (priv->ip6_external_gw) { - nm_log_info (LOGD_VPN, "VPN Gateway: %s", - nm_utils_inet6_ntop (priv->ip6_external_gw, NULL)); + _LOGI ("Data: VPN Gateway: %s", + nm_utils_inet6_ntop (priv->ip6_external_gw, NULL)); } - nm_log_info (LOGD_VPN, "Tunnel Device: %s", priv->ip_iface ? priv->ip_iface : "(none)"); + _LOGI ("Data: Tunnel Device: %s", priv->ip_iface ? priv->ip_iface : "(none)"); if (priv->ip4_config) { - nm_log_info (LOGD_VPN, "IPv4 configuration:"); + _LOGI ("Data: IPv4 configuration:"); address4 = nm_ip4_config_get_address (priv->ip4_config, 0); if (priv->ip4_internal_gw) - nm_log_info (LOGD_VPN, " Internal Gateway: %s", nm_utils_inet4_ntop (priv->ip4_internal_gw, NULL)); - nm_log_info (LOGD_VPN, " Internal Address: %s", nm_utils_inet4_ntop (address4->address, NULL)); - nm_log_info (LOGD_VPN, " Internal Prefix: %d", address4->plen); - nm_log_info (LOGD_VPN, " Internal Point-to-Point Address: %s", nm_utils_inet4_ntop (address4->peer_address, NULL)); - nm_log_info (LOGD_VPN, " Maximum Segment Size (MSS): %d", nm_ip4_config_get_mss (priv->ip4_config)); + _LOGI ("Data: Internal Gateway: %s", nm_utils_inet4_ntop (priv->ip4_internal_gw, NULL)); + _LOGI ("Data: Internal Address: %s", nm_utils_inet4_ntop (address4->address, NULL)); + _LOGI ("Data: Internal Prefix: %d", address4->plen); + _LOGI ("Data: Internal Point-to-Point Address: %s", nm_utils_inet4_ntop (address4->peer_address, NULL)); + _LOGI ("Data: Maximum Segment Size (MSS): %d", nm_ip4_config_get_mss (priv->ip4_config)); num = nm_ip4_config_get_num_routes (priv->ip4_config); for (i = 0; i < num; i++) { const NMPlatformIP4Route *route = nm_ip4_config_get_route (priv->ip4_config, i); - nm_log_info (LOGD_VPN, " Static Route: %s/%d Next Hop: %s", - nm_utils_inet4_ntop (route->network, NULL), - route->plen, - nm_utils_inet4_ntop (route->gateway, buf)); + _LOGI ("Data: Static Route: %s/%d Next Hop: %s", + nm_utils_inet4_ntop (route->network, NULL), + route->plen, + nm_utils_inet4_ntop (route->gateway, buf)); } - nm_log_info (LOGD_VPN, " Forbid Default Route: %s", - nm_ip4_config_get_never_default (priv->ip4_config) ? "yes" : "no"); + _LOGI ("Data: Forbid Default Route: %s", + nm_ip4_config_get_never_default (priv->ip4_config) ? "yes" : "no"); num = nm_ip4_config_get_num_nameservers (priv->ip4_config); for (i = 0; i < num; i++) { - nm_log_info (LOGD_VPN, " Internal DNS: %s", - nm_utils_inet4_ntop (nm_ip4_config_get_nameserver (priv->ip4_config, i), NULL)); + _LOGI ("Data: Internal DNS: %s", + nm_utils_inet4_ntop (nm_ip4_config_get_nameserver (priv->ip4_config, i), NULL)); } if (nm_ip4_config_get_num_domains (priv->ip4_config) > 0) dns_domain = (char *) nm_ip4_config_get_domain (priv->ip4_config, 0); - nm_log_info (LOGD_VPN, " DNS Domain: '%s'", dns_domain ? dns_domain : "(none)"); + _LOGI ("Data: DNS Domain: '%s'", dns_domain ? dns_domain : "(none)"); } else - nm_log_info (LOGD_VPN, "No IPv4 configuration"); + _LOGI ("Data: No IPv4 configuration"); if (priv->ip6_config) { - nm_log_info (LOGD_VPN, "IPv6 configuration:"); + _LOGI ("Data: IPv6 configuration:"); address6 = nm_ip6_config_get_address (priv->ip6_config, 0); if (priv->ip6_internal_gw) - nm_log_info (LOGD_VPN, " Internal Gateway: %s", nm_utils_inet6_ntop (priv->ip6_internal_gw, NULL)); - nm_log_info (LOGD_VPN, " Internal Address: %s", nm_utils_inet6_ntop (&address6->address, NULL)); - nm_log_info (LOGD_VPN, " Internal Prefix: %d", address6->plen); - nm_log_info (LOGD_VPN, " Internal Point-to-Point Address: %s", nm_utils_inet6_ntop (&address6->peer_address, NULL)); - nm_log_info (LOGD_VPN, " Maximum Segment Size (MSS): %d", nm_ip6_config_get_mss (priv->ip6_config)); + _LOGI ("Data: Internal Gateway: %s", nm_utils_inet6_ntop (priv->ip6_internal_gw, NULL)); + _LOGI ("Data: Internal Address: %s", nm_utils_inet6_ntop (&address6->address, NULL)); + _LOGI ("Data: Internal Prefix: %d", address6->plen); + _LOGI ("Data: Internal Point-to-Point Address: %s", nm_utils_inet6_ntop (&address6->peer_address, NULL)); + _LOGI ("Data: Maximum Segment Size (MSS): %d", nm_ip6_config_get_mss (priv->ip6_config)); num = nm_ip6_config_get_num_routes (priv->ip6_config); for (i = 0; i < num; i++) { const NMPlatformIP6Route *route = nm_ip6_config_get_route (priv->ip6_config, i); - nm_log_info (LOGD_VPN, " Static Route: %s/%d Next Hop: %s", - nm_utils_inet6_ntop (&route->network, NULL), - route->plen, - nm_utils_inet6_ntop (&route->gateway, buf)); + _LOGI ("Data: Static Route: %s/%d Next Hop: %s", + nm_utils_inet6_ntop (&route->network, NULL), + route->plen, + nm_utils_inet6_ntop (&route->gateway, buf)); } - nm_log_info (LOGD_VPN, " Forbid Default Route: %s", - nm_ip6_config_get_never_default (priv->ip6_config) ? "yes" : "no"); + _LOGI ("Data: Forbid Default Route: %s", + nm_ip6_config_get_never_default (priv->ip6_config) ? "yes" : "no"); num = nm_ip6_config_get_num_nameservers (priv->ip6_config); for (i = 0; i < num; i++) { - nm_log_info (LOGD_VPN, " Internal DNS: %s", - nm_utils_inet6_ntop (nm_ip6_config_get_nameserver (priv->ip6_config, i), NULL)); + _LOGI ("Data: Internal DNS: %s", + nm_utils_inet6_ntop (nm_ip6_config_get_nameserver (priv->ip6_config, i), NULL)); } if (nm_ip6_config_get_num_domains (priv->ip6_config) > 0) dns_domain = (char *) nm_ip6_config_get_domain (priv->ip6_config, 0); - nm_log_info (LOGD_VPN, " DNS Domain: '%s'", dns_domain ? dns_domain : "(none)"); + _LOGI ("Data: DNS Domain: '%s'", dns_domain ? dns_domain : "(none)"); } else - nm_log_info (LOGD_VPN, "No IPv6 configuration"); + _LOGI ("Data: No IPv6 configuration"); if (priv->banner && strlen (priv->banner)) { - nm_log_info (LOGD_VPN, "Login Banner:"); - nm_log_info (LOGD_VPN, "-----------------------------------------"); - nm_log_info (LOGD_VPN, "%s", priv->banner); - nm_log_info (LOGD_VPN, "-----------------------------------------"); + _LOGI ("Data: Login Banner:"); + _LOGI ("Data: -----------------------------------------"); + _LOGI ("Data: %s", priv->banner); + _LOGI ("Data: -----------------------------------------"); } } static void -apply_parent_device_config (NMVpnConnection *connection) +apply_parent_device_config (NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); - NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (connection)); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (self)); NMIP4Config *vpn4_parent_config = NULL; NMIP6Config *vpn6_parent_config = NULL; - if (priv->ip4_config) - vpn4_parent_config = nm_ip4_config_new (); - if (priv->ip6_config) - vpn6_parent_config = nm_ip6_config_new (); + if (priv->ip_ifindex > 0) { + if (priv->ip4_config) + vpn4_parent_config = nm_ip4_config_new (priv->ip_ifindex); + if (priv->ip6_config) + vpn6_parent_config = nm_ip6_config_new (priv->ip_ifindex); + } else { + int ifindex; - if (priv->ip_ifindex <= 0) { /* If the VPN didn't return a network interface, it is a route-based * VPN (like kernel IPSec) and all IP addressing and routing should * be done on the parent interface instead. @@ -931,38 +1048,38 @@ apply_parent_device_config (NMVpnConnection *connection) /* Also clear the gateway. We don't configure the gateway as part of the * vpn-config. Instead we tell NMDefaultRouteManager directly about the * default route. */ - if (vpn4_parent_config) { + ifindex = nm_device_get_ip_ifindex (parent_dev); + if (priv->ip4_config) { + vpn4_parent_config = nm_ip4_config_new (ifindex); nm_ip4_config_merge (vpn4_parent_config, priv->ip4_config, NM_IP_CONFIG_MERGE_DEFAULT); nm_ip4_config_unset_gateway (vpn4_parent_config); } - if (vpn6_parent_config) { + if (priv->ip6_config) { + vpn6_parent_config = nm_ip6_config_new (ifindex); nm_ip6_config_merge (vpn6_parent_config, priv->ip6_config, NM_IP_CONFIG_MERGE_DEFAULT); nm_ip6_config_set_gateway (vpn6_parent_config, NULL); } } - if (vpn4_parent_config) { - /* Add any explicit route to the VPN gateway through the parent device */ - if (priv->ip4_external_gw) - add_ip4_vpn_gateway_route (vpn4_parent_config, parent_dev, priv->ip4_external_gw); + /* Add any explicit route to the VPN gateway through the parent device */ + if (vpn4_parent_config && priv->ip4_external_gw) + add_ip4_vpn_gateway_route (vpn4_parent_config, parent_dev, priv->ip4_external_gw); + if (vpn6_parent_config && priv->ip6_external_gw) + add_ip6_vpn_gateway_route (vpn6_parent_config, parent_dev, priv->ip6_external_gw); - nm_device_set_vpn4_config (parent_dev, vpn4_parent_config); - g_object_unref (vpn4_parent_config); - } - if (vpn6_parent_config) { - /* Add any explicit route to the VPN gateway through the parent device */ - if (priv->ip6_external_gw) - add_ip6_vpn_gateway_route (vpn6_parent_config, parent_dev, priv->ip6_external_gw); + nm_device_replace_vpn4_config (parent_dev, priv->last_device_ip4_config, vpn4_parent_config); + g_clear_object (&priv->last_device_ip4_config); + priv->last_device_ip4_config = vpn4_parent_config; - nm_device_set_vpn6_config (parent_dev, vpn6_parent_config); - g_object_unref (vpn6_parent_config); - } + nm_device_replace_vpn6_config (parent_dev, priv->last_device_ip6_config, vpn6_parent_config); + g_clear_object (&priv->last_device_ip6_config); + priv->last_device_ip6_config = vpn6_parent_config; } static gboolean -nm_vpn_connection_apply_config (NMVpnConnection *connection) +nm_vpn_connection_apply_config (NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); if (priv->ip_ifindex > 0) { nm_platform_link_set_up (NM_PLATFORM_GET, priv->ip_ifindex, NULL); @@ -970,7 +1087,7 @@ nm_vpn_connection_apply_config (NMVpnConnection *connection) if (priv->ip4_config) { if (!nm_ip4_config_commit (priv->ip4_config, priv->ip_ifindex, TRUE, - nm_vpn_connection_get_ip4_route_metric (connection))) + nm_vpn_connection_get_ip4_route_metric (self))) return FALSE; } @@ -985,56 +1102,60 @@ nm_vpn_connection_apply_config (NMVpnConnection *connection) nm_platform_link_set_mtu (NM_PLATFORM_GET, priv->ip_ifindex, priv->mtu); } - apply_parent_device_config (connection); + apply_parent_device_config (self); - nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), connection); - nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), connection); + nm_default_route_manager_ip4_update_default_route (priv->default_route_manager, self); + nm_default_route_manager_ip6_update_default_route (priv->default_route_manager, self); - nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) complete.", - nm_connection_get_id (priv->connection)); - _set_vpn_state (connection, STATE_PRE_UP, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _LOGI ("VPN connection: (IP Config Get) complete"); + _set_vpn_state (self, STATE_PRE_UP, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); return TRUE; } static void -_cleanup_failed_config (NMVpnConnection *connection) +_cleanup_failed_config (NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - g_clear_object (&priv->ip4_config); - g_clear_object (&priv->ip6_config); + nm_exported_object_clear_and_unexport (&priv->ip4_config); + nm_exported_object_clear_and_unexport (&priv->ip6_config); - nm_log_warn (LOGD_VPN, "VPN connection '%s' did not receive valid IP config information.", - nm_connection_get_id (priv->connection)); - _set_vpn_state (connection, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID, FALSE); + _LOGW ("VPN connection: did not receive valid IP config information"); + _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID, FALSE); } static void -fw_change_zone_cb (GError *error, gpointer user_data) +fw_change_zone_cb (NMFirewallManager *firewall_manager, + NMFirewallManagerCallId call_id, + GError *error, + gpointer user_data) { - NMVpnConnection *connection = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMVpnConnection *self = user_data; + NMVpnConnectionPrivate *priv; - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; + g_return_if_fail (NM_IS_VPN_CONNECTION (self)); + + priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + g_return_if_fail (priv->fw_call == call_id); priv->fw_call = NULL; + if (nm_utils_error_is_cancelled (error, FALSE)) + return; + if (error) { - nm_log_warn (LOGD_VPN, "VPN connection '%s': setting firewall zone failed: '%s'", - nm_connection_get_id (priv->connection), error->message); // FIXME: fail the activation? } - if (!nm_vpn_connection_apply_config (connection)) - _cleanup_failed_config (connection); + if (!nm_vpn_connection_apply_config (self)) + _cleanup_failed_config (self); } static void -nm_vpn_connection_config_maybe_complete (NMVpnConnection *connection, +nm_vpn_connection_config_maybe_complete (NMVpnConnection *self, gboolean success) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); NMConnection *base_con; NMSettingConnection *s_con; const char *zone; @@ -1050,650 +1171,609 @@ nm_vpn_connection_config_maybe_complete (NMVpnConnection *connection, } } - if (priv->connect_timeout) { - g_source_remove (priv->connect_timeout); - priv->connect_timeout = 0; - } + nm_clear_g_source (&priv->connect_timeout); if (success) { - print_vpn_config (connection); + print_vpn_config (self); /* Add the tunnel interface to the specified firewall zone */ if (priv->ip_iface) { - base_con = nm_vpn_connection_get_connection (connection); - g_assert (base_con); + base_con = _get_applied_connection (self); s_con = nm_connection_get_setting_connection (base_con); zone = nm_setting_connection_get_zone (s_con); - nm_log_dbg (LOGD_VPN, "VPN connection '%s': setting firewall zone '%s' for '%s'", - nm_connection_get_id (base_con), zone ? zone : "default", priv->ip_iface); - fw_call_cleanup (connection); + _LOGD ("setting firewall zone %s%s%s for '%s'", + NM_PRINT_FMT_QUOTED (zone, "'", zone, "'", "(default)"), + priv->ip_iface); + fw_call_cleanup (self); priv->fw_call = nm_firewall_manager_add_or_change_zone (nm_firewall_manager_get (), priv->ip_iface, zone, FALSE, fw_change_zone_cb, - connection); + self); return; } else - if (nm_vpn_connection_apply_config (connection)) + if (nm_vpn_connection_apply_config (self)) return; } - _cleanup_failed_config (connection); + _cleanup_failed_config (self); } -#define LOG_INVALID_ARG(property) \ - nm_log_dbg (LOGD_VPN, "VPN connection '%s' has invalid argument %s", \ - nm_connection_get_id (priv->connection), property) +static gboolean +ip6_addr_from_variant (GVariant *v, struct in6_addr *addr) +{ + const guint8 *bytes; + gsize len; + + g_return_val_if_fail (v, FALSE); + g_return_val_if_fail (addr, FALSE); + + if (g_variant_is_of_type (v, G_VARIANT_TYPE ("ay"))) { + bytes = g_variant_get_fixed_array (v, &len, sizeof (guint8)); + if (len == sizeof (struct in6_addr) && !IN6_IS_ADDR_UNSPECIFIED (bytes)) { + memcpy (addr, bytes, len); + return TRUE; + } + } + return FALSE; +} + +static struct in6_addr * +ip6_addr_dup_from_variant (GVariant *v) +{ + struct in6_addr *addr; + + addr = g_malloc0 (sizeof (*addr)); + if (ip6_addr_from_variant (v, addr)) + return addr; + g_free (addr); + return NULL; +} static gboolean -process_generic_config (NMVpnConnection *connection, - GHashTable *config_hash) +process_generic_config (NMVpnConnection *self, GVariant *dict) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); - GValue *val; + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + const char *str; + GVariant *v; + guint32 u32; + gboolean b, success = FALSE; - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CAN_PERSIST); - if (val && G_VALUE_HOLDS_BOOLEAN (val) && g_value_get_boolean (val)) { + if (g_variant_lookup (dict, NM_VPN_PLUGIN_CAN_PERSIST, "b", &b) && b) { /* Defaults to FALSE, so only let service indicate TRUE */ priv->service_can_persist = TRUE; } g_clear_pointer (&priv->ip_iface, g_free); - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_TUNDEV); - if (val) { - if (G_VALUE_HOLDS (val, G_TYPE_STRING)) { - const char *tmp = g_value_get_string (val); - - /* Backwards compat with NM-openswan */ - if (g_strcmp0 (tmp, "_none_") != 0) - priv->ip_iface = g_strdup (tmp); - } else - LOG_INVALID_ARG (NM_VPN_PLUGIN_CONFIG_TUNDEV); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_TUNDEV, "&s", &str)) { + /* Backwards compat with NM-openswan */ + if (g_strcmp0 (str, "_none_") != 0) + priv->ip_iface = g_strdup (str); } if (priv->ip_iface) { /* Grab the interface index for address/routing operations */ priv->ip_ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface); - if (!priv->ip_ifindex) { - nm_log_err (LOGD_VPN, "(%s): failed to look up VPN interface index", priv->ip_iface); - nm_vpn_connection_config_maybe_complete (connection, FALSE); + if (priv->ip_ifindex <= 0) { + _LOGE ("failed to look up VPN interface index for \"%s\"", priv->ip_iface); + nm_vpn_connection_config_maybe_complete (self, FALSE); return FALSE; } } g_clear_pointer (&priv->banner, g_free); - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_BANNER); - if (val) { - if (G_VALUE_HOLDS (val, G_TYPE_STRING)) - priv->banner = g_strdup (g_value_get_string (val)); - else - LOG_INVALID_ARG (NM_VPN_PLUGIN_CONFIG_BANNER); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_BANNER, "&s", &str)) { + priv->banner = g_strdup (str); + g_object_notify (G_OBJECT (self), NM_VPN_CONNECTION_BANNER); } /* External world-visible address of the VPN server */ priv->ip4_external_gw = 0; g_clear_pointer (&priv->ip6_external_gw, g_free); - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY); - if (val) { - GByteArray *ba; - - if (G_VALUE_HOLDS (val, G_TYPE_UINT)) { - priv->ip4_external_gw = g_value_get_uint (val); - } else if (G_VALUE_HOLDS (val, DBUS_TYPE_G_UCHAR_ARRAY) && - (ba = g_value_get_boxed (val)) && - ba->len == sizeof (struct in6_addr)) { - priv->ip6_external_gw = g_memdup (ba->data, ba->len); - } else { - nm_log_err (LOGD_VPN, "(%s): VPN gateway is neither IPv4 nor IPv6", priv->ip_iface); - nm_vpn_connection_config_maybe_complete (connection, FALSE); - return FALSE; - } + + if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, "u", &u32)) { + priv->ip4_external_gw = u32; + success = TRUE; + } else if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, "@ay", &v)) { + priv->ip6_external_gw = ip6_addr_dup_from_variant (v); + success = !!priv->ip6_external_gw; + g_variant_unref (v); } - priv->mtu = 0; - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_MTU); - if (val) { - if (G_VALUE_HOLDS (val, G_TYPE_UINT)) { - priv->mtu = g_value_get_uint (val); - } else - LOG_INVALID_ARG (NM_VPN_PLUGIN_CONFIG_MTU); + if (!success) { + _LOGE ("VPN gateway is neither IPv4 nor IPv6"); + nm_vpn_connection_config_maybe_complete (self, FALSE); + return FALSE; } + priv->mtu = 0; + if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_MTU, "u", &u32)) + priv->mtu = u32; + return TRUE; } static void -nm_vpn_connection_config_get (DBusGProxy *proxy, - GHashTable *config_hash, - gpointer user_data) +nm_vpn_connection_config_get (NMVpnConnection *self, GVariant *dict) { - NMVpnConnection *connection = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); - GValue *val; + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + gboolean b; - nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) reply received.", - nm_connection_get_id (priv->connection)); + g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT)); + + _LOGI ("VPN connection: (IP Config Get) reply received."); if (priv->vpn_state == STATE_CONNECT) - _set_vpn_state (connection, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); - if (!process_generic_config (connection, config_hash)) + if (!process_generic_config (self, dict)) return; /* Note whether to expect IPv4 and IPv6 configs */ - val = g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_HAS_IP4); priv->has_ip4 = FALSE; - if (val) { - if (G_VALUE_HOLDS (val, G_TYPE_BOOLEAN)) - priv->has_ip4 = g_value_get_boolean (val); - else - LOG_INVALID_ARG (NM_VPN_PLUGIN_CONFIG_HAS_IP4); - } - g_clear_object (&priv->ip4_config); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_HAS_IP4, "b", &b)) + priv->has_ip4 = b; + nm_exported_object_clear_and_unexport (&priv->ip4_config); - val = g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_HAS_IP6); priv->has_ip6 = FALSE; - if (val) { - if (G_VALUE_HOLDS (val, G_TYPE_BOOLEAN)) - priv->has_ip6 = g_value_get_boolean (val); - else - LOG_INVALID_ARG (NM_VPN_PLUGIN_CONFIG_HAS_IP6); - } - g_clear_object (&priv->ip6_config); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_CONFIG_HAS_IP6, "b", &b)) + priv->has_ip6 = b; + nm_exported_object_clear_and_unexport (&priv->ip6_config); } guint32 -nm_vpn_connection_get_ip4_route_metric (NMVpnConnection *connection) +nm_vpn_connection_get_ip4_route_metric (NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); - - if (priv->connection) { - gint64 route_metric = nm_setting_ip_config_get_route_metric (nm_connection_get_setting_ip4_config (priv->connection)); + gint64 route_metric; + NMConnection *applied; - if (route_metric >= 0) - return route_metric; - } + applied = _get_applied_connection (self); + route_metric = nm_setting_ip_config_get_route_metric (nm_connection_get_setting_ip4_config (applied)); - return NM_VPN_ROUTE_METRIC_DEFAULT; + return (route_metric >= 0) ? route_metric : NM_VPN_ROUTE_METRIC_DEFAULT; } guint32 -nm_vpn_connection_get_ip6_route_metric (NMVpnConnection *connection) +nm_vpn_connection_get_ip6_route_metric (NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + gint64 route_metric; + NMConnection *applied; - if (priv->connection) { - gint64 route_metric = nm_setting_ip_config_get_route_metric (nm_connection_get_setting_ip6_config (priv->connection)); + applied = _get_applied_connection (self); + route_metric = nm_setting_ip_config_get_route_metric (nm_connection_get_setting_ip6_config (applied)); - if (route_metric >= 0) - return route_metric; - } - - return NM_VPN_ROUTE_METRIC_DEFAULT; + return (route_metric >= 0) ? route_metric : NM_VPN_ROUTE_METRIC_DEFAULT; } static void -nm_vpn_connection_ip4_config_get (DBusGProxy *proxy, - GHashTable *config_hash, - gpointer user_data) +nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) { - NMVpnConnection *connection = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); NMPlatformIP4Address address; NMIP4Config *config; - GValue *val; - int i; - guint32 route_metric; + guint32 u32, route_metric; + GVariantIter *iter; + const char *str; + GVariant *v; + gboolean b; + int ifindex; + + g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT)); if (priv->vpn_state == STATE_CONNECT) - _set_vpn_state (connection, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); if (priv->has_ip4) { - nm_log_info (LOGD_VPN, "VPN connection '%s' (IP4 Config Get) reply received.", - nm_connection_get_id (priv->connection)); + _LOGI ("VPN connection: (IP4 Config Get) reply received"); - if (g_hash_table_size (config_hash) == 0) { + if (g_variant_n_children (dict) == 0) { priv->has_ip4 = FALSE; - nm_vpn_connection_config_maybe_complete (connection, TRUE); + nm_vpn_connection_config_maybe_complete (self, TRUE); return; } } else { - nm_log_info (LOGD_VPN, "VPN connection '%s' (IP4 Config Get) reply received from old-style plugin.", - nm_connection_get_id (priv->connection)); + _LOGI ("VPN connection: (IP4 Config Get) reply received from old-style plugin"); /* In the old API, the generic and IPv4 configuration items * were mixed together. */ - if (!process_generic_config (connection, config_hash)) + if (!process_generic_config (self, dict)) return; priv->has_ip4 = TRUE; priv->has_ip6 = FALSE; } - config = nm_ip4_config_new (); + if (priv->ip_ifindex > 0) { + ifindex = priv->ip_ifindex; + } else { + NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (self)); + ifindex = nm_device_get_ip_ifindex (parent_dev); + } + config = nm_ip4_config_new (ifindex); memset (&address, 0, sizeof (address)); address.plen = 24; /* Internal address of the VPN subnet's gateway */ - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY); - if (val) { - priv->ip4_internal_gw = g_value_get_uint (val); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY, "u", &u32)) { + priv->ip4_internal_gw = u32; nm_ip4_config_set_gateway (config, priv->ip4_internal_gw); } - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS); - if (val) - address.address = g_value_get_uint (val); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, "u", &u32)) + address.address = u32; - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_PTP); - if (val) - address.peer_address = g_value_get_uint (val); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_PTP, "u", &u32)) + address.peer_address = u32; + else + address.peer_address = address.address; - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX); - if (val) - address.plen = g_value_get_uint (val); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, "u", &u32)) + address.plen = u32; if (address.address && address.plen) { address.source = NM_IP_CONFIG_SOURCE_VPN; nm_ip4_config_add_address (config, &address); } else { - nm_log_err (LOGD_VPN, "invalid IP4 config received!"); + _LOGE ("invalid IP4 config received!"); g_object_unref (config); - nm_vpn_connection_config_maybe_complete (connection, FALSE); + nm_vpn_connection_config_maybe_complete (self, FALSE); return; } - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DNS); - if (val) { - GArray *dns = (GArray *) g_value_get_boxed (val); - - for (i = 0; i < dns->len; i++) - nm_ip4_config_add_nameserver (config, g_array_index (dns, guint, i)); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_DNS, "au", &iter)) { + while (g_variant_iter_next (iter, "u", &u32)) + nm_ip4_config_add_nameserver (config, u32); + g_variant_iter_free (iter); } - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_NBNS); - if (val) { - GArray *nbns = (GArray *) g_value_get_boxed (val); - - for (i = 0; i < nbns->len; i++) - nm_ip4_config_add_wins (config, g_array_index (nbns, guint, i)); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_NBNS, "au", &iter)) { + while (g_variant_iter_next (iter, "u", &u32)) + nm_ip4_config_add_wins (config, u32); + g_variant_iter_free (iter); } - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_MSS); - if (val) - nm_ip4_config_set_mss (config, g_value_get_uint (val)); - - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN); - if (val) - nm_ip4_config_add_domain (config, g_value_get_string (val)); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_MSS, "u", &u32)) + nm_ip4_config_set_mss (config, u32); - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_DOMAINS); - if (val) { - const char **domains = g_value_get_boxed (val); - const char **domain; + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN, "&s", &str)) + nm_ip4_config_add_domain (config, str); - for (domain = domains; domain && *domain; domain++) - nm_ip4_config_add_domain (config, *domain); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_DOMAINS, "as", &iter)) { + while (g_variant_iter_next (iter, "&s", &str)) + nm_ip4_config_add_domain (config, str); + g_variant_iter_free (iter); } - route_metric = nm_vpn_connection_get_ip4_route_metric (connection); + route_metric = nm_vpn_connection_get_ip4_route_metric (self); - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES); - if (val) { - GSList *routes; - GSList *iter; + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES, "aau", &iter)) { + while (g_variant_iter_next (iter, "@au", &v)) { + NMPlatformIP4Route route = { 0, }; - routes = nm_utils_ip4_routes_from_gvalue (val); - for (iter = routes; iter; iter = iter->next) { - NMIPRoute *item = iter->data; - NMPlatformIP4Route route; + switch (g_variant_n_children (v)) { + case 5: + g_variant_get_child (v, 4, "u", &route.pref_src); + /* fallthrough */ + case 4: + g_variant_get_child (v, 0, "u", &route.network); + g_variant_get_child (v, 1, "u", &route.plen); + g_variant_get_child (v, 2, "u", &route.gateway); + /* 4th item is unused route metric */ + route.metric = route_metric; + route.source = NM_IP_CONFIG_SOURCE_VPN; - memset (&route, 0, sizeof (route)); - nm_ip_route_get_dest_binary (item, &route.network); - route.plen = nm_ip_route_get_prefix (item); - nm_ip_route_get_next_hop_binary (item, &route.gateway); - route.source = NM_IP_CONFIG_SOURCE_VPN; - route.metric = route_metric; - - /* Ignore host routes to the VPN gateway since NM adds one itself - * below. Since NM knows more about the routing situation than - * the VPN server, we want to use the NM created route instead of - * whatever the server provides. - */ - if (priv->ip4_external_gw && route.network == priv->ip4_external_gw && route.plen == 32) - continue; - - /* Otherwise accept the VPN-provided route */ - nm_ip4_config_add_route (config, &route); + /* Ignore host routes to the VPN gateway since NM adds one itself + * below. Since NM knows more about the routing situation than + * the VPN server, we want to use the NM created route instead of + * whatever the server provides. + */ + if (!(priv->ip4_external_gw && route.network == priv->ip4_external_gw && route.plen == 32)) + nm_ip4_config_add_route (config, &route); + break; + default: + _LOGW ("VPN connection: received invalid IPv4 route"); + } + g_variant_unref (v); } - - g_slist_free_full (routes, (GDestroyNotify) nm_ip_route_unref); + g_variant_iter_free (iter); } - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT); - if (val && G_VALUE_HOLDS_BOOLEAN (val)) - nm_ip4_config_set_never_default (config, g_value_get_boolean (val)); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT, "b", &b)) + nm_ip4_config_set_never_default (config, b); /* Merge in user overrides from the NMConnection's IPv4 setting */ nm_ip4_config_merge_setting (config, - nm_connection_get_setting_ip4_config (priv->connection), + nm_connection_get_setting_ip4_config (_get_applied_connection (self)), route_metric); - g_clear_object (&priv->ip4_config); + nm_exported_object_clear_and_unexport (&priv->ip4_config); priv->ip4_config = config; - nm_ip4_config_export (config); - g_object_notify (G_OBJECT (connection), NM_ACTIVE_CONNECTION_IP4_CONFIG); - nm_vpn_connection_config_maybe_complete (connection, TRUE); + nm_exported_object_export (NM_EXPORTED_OBJECT (config)); + g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_IP4_CONFIG); + nm_vpn_connection_config_maybe_complete (self, TRUE); } static void -nm_vpn_connection_ip6_config_get (DBusGProxy *proxy, - GHashTable *config_hash, - gpointer user_data) +nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict) { - NMVpnConnection *connection = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); NMPlatformIP6Address address; + guint32 u32, route_metric; NMIP6Config *config; - GValue *val; - int i; - guint32 route_metric; + GVariantIter *iter; + const char *str; + GVariant *v; + gboolean b; - nm_log_info (LOGD_VPN, "VPN connection '%s' (IP6 Config Get) reply received.", - nm_connection_get_id (priv->connection)); + g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT)); + + _LOGI ("VPN connection: (IP6 Config Get) reply received"); if (priv->vpn_state == STATE_CONNECT) - _set_vpn_state (connection, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_IP_CONFIG_GET, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); - if (g_hash_table_size (config_hash) == 0) { + if (g_variant_n_children (dict) == 0) { priv->has_ip6 = FALSE; - nm_vpn_connection_config_maybe_complete (connection, TRUE); + nm_vpn_connection_config_maybe_complete (self, TRUE); return; } - config = nm_ip6_config_new (); + config = nm_ip6_config_new (priv->ip_ifindex); memset (&address, 0, sizeof (address)); address.plen = 128; /* Internal address of the VPN subnet's gateway */ g_clear_pointer (&priv->ip6_internal_gw, g_free); - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_INT_GATEWAY); - if (val) { - GByteArray *ba = g_value_get_boxed (val); - - if (ba->len == sizeof (struct in6_addr)) { - priv->ip6_internal_gw = g_memdup (ba->data, ba->len); - nm_ip6_config_set_gateway (config, priv->ip6_internal_gw); - } + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_INT_GATEWAY, "@ay", &v)) { + priv->ip6_internal_gw = ip6_addr_dup_from_variant (v); + nm_ip6_config_set_gateway (config, priv->ip6_internal_gw); + g_variant_unref (v); } - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS); - if (val) { - GByteArray *ba = g_value_get_boxed (val); - - if (ba->len == sizeof (struct in6_addr)) - address.address = *(struct in6_addr *) ba->data; + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS, "@ay", &v)) { + ip6_addr_from_variant (v, &address.address); + g_variant_unref (v); } - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_PTP); - if (val) { - GByteArray *ba = g_value_get_boxed (val); - - if (ba->len == sizeof (struct in6_addr)) - address.peer_address = *(struct in6_addr *) ba->data; + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_PTP, "@ay", &v)) { + ip6_addr_from_variant (v, &address.peer_address); + g_variant_unref (v); } - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_PREFIX); - if (val) - address.plen = g_value_get_uint (val); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_PREFIX, "u", &u32)) + address.plen = u32; if (!IN6_IS_ADDR_UNSPECIFIED (&address.address) && address.plen) { address.source = NM_IP_CONFIG_SOURCE_VPN; nm_ip6_config_add_address (config, &address); } else { - nm_log_err (LOGD_VPN, "invalid IP6 config received!"); + _LOGE ("invalid IP6 config received!"); g_object_unref (config); - nm_vpn_connection_config_maybe_complete (connection, FALSE); + nm_vpn_connection_config_maybe_complete (self, FALSE); + return; } - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_DNS); - if (val) { - GPtrArray *dns = (GPtrArray *) g_value_get_boxed (val); - GByteArray *ba; + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_DNS, "aay", &iter)) { + while (g_variant_iter_next (iter, "@ay", &v)) { + struct in6_addr dns; - for (i = 0; i < dns->len; i++) { - ba = dns->pdata[i]; - if (ba->len == sizeof (struct in6_addr)) - nm_ip6_config_add_nameserver (config, (struct in6_addr *)ba->data); + if (ip6_addr_from_variant (v, &dns)) + nm_ip6_config_add_nameserver (config, &dns); + g_variant_unref (v); } + g_variant_iter_free (iter); } - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_MSS); - if (val) - nm_ip6_config_set_mss (config, g_value_get_uint (val)); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_MSS, "u", &u32)) + nm_ip6_config_set_mss (config, u32); - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_DOMAIN); - if (val) - nm_ip6_config_add_domain (config, g_value_get_string (val)); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_DOMAIN, "&s", &str)) + nm_ip6_config_add_domain (config, str); - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_DOMAINS); - if (val) { - const char **domains = g_value_get_boxed (val); - const char **domain; - - for (domain = domains; domain && *domain; domain++) - nm_ip6_config_add_domain (config, *domain); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_DOMAINS, "as", &iter)) { + while (g_variant_iter_next (iter, "&s", &str)) + nm_ip6_config_add_domain (config, str); + g_variant_iter_free (iter); } - route_metric = nm_vpn_connection_get_ip6_route_metric (connection); + route_metric = nm_vpn_connection_get_ip6_route_metric (self); - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES); - if (val) { - GSList *routes; - GSList *iter; + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, "a(ayuayu)", &iter)) { + GVariant *dest, *next_hop; + guint32 prefix, metric; - routes = nm_utils_ip6_routes_from_gvalue (val); - for (iter = routes; iter; iter = iter->next) { - NMIPRoute *item = iter->data; + while (g_variant_iter_next (iter, "(@ayu@ayu)", &dest, &prefix, &next_hop, &metric)) { NMPlatformIP6Route route; memset (&route, 0, sizeof (route)); - nm_ip_route_get_dest_binary (item, &route.network); - route.plen = nm_ip_route_get_prefix (item); - nm_ip_route_get_next_hop_binary (item, &route.gateway); - route.source = NM_IP_CONFIG_SOURCE_VPN; + + if (!ip6_addr_from_variant (dest, &route.network)) { + _LOGW ("VPN connection: received invalid IPv6 dest address"); + goto next; + } + + route.plen = prefix; + ip6_addr_from_variant (next_hop, &route.gateway); route.metric = route_metric; + route.source = NM_IP_CONFIG_SOURCE_VPN; - /* Ignore host routes to the VPN gateway since NM adds one itself - * below. Since NM knows more about the routing situation than - * the VPN server, we want to use the NM created route instead of - * whatever the server provides. + /* Ignore host routes to the VPN gateway since NM adds one itself. + * Since NM knows more about the routing situation than the VPN + * server, we want to use the NM created route instead of whatever + * the server provides. */ - if (priv->ip6_external_gw && IN6_ARE_ADDR_EQUAL (&route.network, priv->ip6_external_gw) && route.plen == 128) - continue; + if (!(priv->ip6_external_gw && IN6_ARE_ADDR_EQUAL (&route.network, priv->ip6_external_gw) && route.plen == 128)) + nm_ip6_config_add_route (config, &route); - /* Otherwise accept the VPN-provided route */ - nm_ip6_config_add_route (config, &route); +next: + g_variant_unref (dest); + g_variant_unref (next_hop); } - - g_slist_free_full (routes, (GDestroyNotify) nm_ip_route_unref); + g_variant_iter_free (iter); } - val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT); - if (val && G_VALUE_HOLDS_BOOLEAN (val)) - nm_ip6_config_set_never_default (config, g_value_get_boolean (val)); + if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT, "b", &b)) + nm_ip6_config_set_never_default (config, b); /* Merge in user overrides from the NMConnection's IPv6 setting */ nm_ip6_config_merge_setting (config, - nm_connection_get_setting_ip6_config (priv->connection), + nm_connection_get_setting_ip6_config (_get_applied_connection (self)), route_metric); - g_clear_object (&priv->ip6_config); + nm_exported_object_clear_and_unexport (&priv->ip6_config); priv->ip6_config = config; - nm_ip6_config_export (config); - g_object_notify (G_OBJECT (connection), NM_ACTIVE_CONNECTION_IP6_CONFIG); - nm_vpn_connection_config_maybe_complete (connection, TRUE); + nm_exported_object_export (NM_EXPORTED_OBJECT (config)); + g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_IP6_CONFIG); + nm_vpn_connection_config_maybe_complete (self, TRUE); } static gboolean connect_timeout_cb (gpointer user_data) { - NMVpnConnection *connection = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMVpnConnection *self = NM_VPN_CONNECTION (user_data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); priv->connect_timeout = 0; /* Cancel activation if it's taken too long */ if (priv->vpn_state == STATE_CONNECT || priv->vpn_state == STATE_IP_CONFIG_GET) { - nm_log_warn (LOGD_VPN, "VPN connection '%s' connect timeout exceeded.", - nm_connection_get_id (priv->connection)); - _set_vpn_state (connection, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, FALSE); + _LOGW ("VPN connection: connect timeout exceeded."); + _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, FALSE); } return FALSE; } static void -connect_success (NMVpnConnection *connection) +connect_success (NMVpnConnection *self) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + NMSettingVpn *s_vpn; + guint32 timeout; + + s_vpn = nm_connection_get_setting_vpn (_get_applied_connection (self)); + g_assert (s_vpn); - /* 40 second timeout waiting for IP config signal from VPN service */ - priv->connect_timeout = g_timeout_add_seconds (40, connect_timeout_cb, connection); + /* Timeout waiting for IP config signal from VPN service + * It is a configured value or 60 seconds */ + timeout = nm_setting_vpn_get_timeout (s_vpn); + if (timeout == 0) { + char *value; + + value = nm_config_data_get_connection_default (NM_CONFIG_GET_DATA, + "vpn.timeout", NULL); + timeout = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, 60); + timeout = timeout == 0 ? 60 : timeout; + g_free (value); + } + priv->connect_timeout = g_timeout_add_seconds (timeout, connect_timeout_cb, self); - g_hash_table_destroy (priv->connect_hash); - priv->connect_hash = NULL; + g_clear_pointer (&priv->connect_hash, g_variant_unref); } static void -connect_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data) +connect_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { - NMVpnConnection *self = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - GError *err = NULL; - - nm_log_info (LOGD_VPN, "VPN connection '%s' (Connect) reply received.", - nm_connection_get_id (priv->connection)); + NMVpnConnection *self; + gs_unref_variant GVariant *reply = NULL; + gs_free_error GError *error = NULL; - dbus_g_proxy_end_call (proxy, call, &err, G_TYPE_INVALID); - if (!err) { - connect_success (self); + reply = g_dbus_proxy_call_finish (proxy, result, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - } - nm_log_warn (LOGD_VPN, "VPN connection '%s' failed to connect: '%s'.", - nm_connection_get_id (priv->connection), err->message); - g_error_free (err); - _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE); + self = NM_VPN_CONNECTION (user_data); + + if (error) { + g_dbus_error_strip_remote_error (error); + _LOGW ("VPN connection: failed to connect: '%s'", + error->message); + _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE); + } else + connect_success (self); } static void -connect_interactive_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data) +connect_interactive_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { - NMVpnConnection *self = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - GError *err = NULL; - - nm_log_info (LOGD_VPN, "VPN connection '%s' (ConnectInteractive) reply received.", - nm_connection_get_id (priv->connection)); + NMVpnConnection *self; + NMVpnConnectionPrivate *priv; + gs_unref_variant GVariant *reply = NULL; + gs_free_error GError *error = NULL; - dbus_g_proxy_end_call (proxy, call, &err, G_TYPE_INVALID); - if (!err) { - connect_success (self); + reply = g_dbus_proxy_call_finish (proxy, result, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; - } - if (dbus_g_error_has_name (err, NM_DBUS_VPN_ERROR_PREFIX "." NM_DBUS_VPN_INTERACTIVE_NOT_SUPPORTED)) { + self = NM_VPN_CONNECTION (user_data); + priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + + _LOGI ("VPN connection: (ConnectInteractive) reply received"); + + if (g_error_matches (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_INTERACTIVE_NOT_SUPPORTED)) { + _LOGD ("VPN connection: falling back to non-interactive connect"); + /* Fall back to Connect() */ - dbus_g_proxy_begin_call (priv->proxy, "Connect", - connect_cb, self, NULL, - DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, priv->connect_hash, - G_TYPE_INVALID); - } else { - nm_log_warn (LOGD_VPN, "VPN connection '%s' failed to connect interactively: '%s'.", - nm_connection_get_id (priv->connection), err->message); - g_error_free (err); + g_dbus_proxy_call (priv->proxy, + "Connect", + g_variant_new ("(@a{sa{sv}})", priv->connect_hash), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + (GAsyncReadyCallback) connect_cb, + self); + } else if (error) { + g_dbus_error_strip_remote_error (error); + _LOGW ("VPN connection: failed to connect interactively: '%s'", + error->message); _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE); - } + } else + connect_success (self); } /* Add a username to a hashed connection */ -static GHashTable * +static GVariant * _hash_with_username (NMConnection *connection, const char *username) { - NMConnection *dup; + gs_unref_object NMConnection *dup = NULL; NMSettingVpn *s_vpn; - GHashTable *hash; - GVariant *dict; - const char *existing; /* Shortcut if we weren't given a username or if there already was one in * the VPN setting; don't bother duplicating the connection and everything. */ s_vpn = nm_connection_get_setting_vpn (connection); g_assert (s_vpn); - existing = nm_setting_vpn_get_user_name (s_vpn); - if (username == NULL || existing) { - dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL); - hash = nm_utils_connection_dict_to_hash (dict); - g_variant_unref (dict); - return hash; - } + if (username == NULL || nm_setting_vpn_get_user_name (s_vpn)) + return nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL); dup = nm_simple_connection_new_clone (connection); g_assert (dup); s_vpn = nm_connection_get_setting_vpn (dup); g_assert (s_vpn); g_object_set (s_vpn, NM_SETTING_VPN_USER_NAME, username, NULL); - dict = nm_connection_to_dbus (dup, NM_CONNECTION_SERIALIZE_ALL); - g_object_unref (dup); - - hash = nm_utils_connection_dict_to_hash (dict); - g_variant_unref (dict); - return hash; + return nm_connection_to_dbus (dup, NM_CONNECTION_SERIALIZE_ALL); } static void -really_activate (NMVpnConnection *connection, const char *username) +really_activate (NMVpnConnection *self, const char *username) { NMVpnConnectionPrivate *priv; - GHashTable *details; + GVariantBuilder details; - g_return_if_fail (NM_IS_VPN_CONNECTION (connection)); + g_return_if_fail (NM_IS_VPN_CONNECTION (self)); - priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + priv = NM_VPN_CONNECTION_GET_PRIVATE (self); g_return_if_fail (priv->vpn_state == STATE_NEED_AUTH); - dbus_g_object_register_marshaller (g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, G_TYPE_VALUE, G_TYPE_INVALID); - - dbus_g_proxy_add_signal (priv->proxy, "Config", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "Config", - G_CALLBACK (nm_vpn_connection_config_get), - connection, NULL); - - /* Ip4Config signal */ - dbus_g_proxy_add_signal (priv->proxy, "Ip4Config", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "Ip4Config", - G_CALLBACK (nm_vpn_connection_ip4_config_get), - connection, NULL); - - /* Ip6Config signal */ - dbus_g_proxy_add_signal (priv->proxy, "Ip6Config", DBUS_TYPE_G_MAP_OF_VARIANT, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "Ip6Config", - G_CALLBACK (nm_vpn_connection_ip6_config_get), - connection, NULL); - - if (priv->connect_hash) - g_hash_table_destroy (priv->connect_hash); - priv->connect_hash = _hash_with_username (priv->connection, username); - details = g_hash_table_new (g_str_hash, g_str_equal); + g_clear_pointer (&priv->connect_hash, g_variant_unref); + priv->connect_hash = _hash_with_username (_get_applied_connection (self), username); + g_variant_ref_sink (priv->connect_hash); /* If at least one agent doesn't support VPN hints, then we can't use * ConnectInteractive(), because that agent won't be able to pass hints @@ -1702,183 +1782,386 @@ really_activate (NMVpnConnection *connection, const char *username) * the old Connect() call. */ if (nm_agent_manager_all_agents_have_capability (nm_agent_manager_get (), - nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (connection)), + nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (self)), NM_SECRET_AGENT_CAPABILITY_VPN_HINTS)) { - nm_log_dbg (LOGD_VPN, "Allowing interactive secrets as all agents have that capability"); - dbus_g_proxy_begin_call (priv->proxy, "ConnectInteractive", - connect_interactive_cb, connection, NULL, - DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, priv->connect_hash, - DBUS_TYPE_G_MAP_OF_VARIANT, details, - G_TYPE_INVALID); + _LOGD ("Allowing interactive secrets as all agents have that capability"); + + g_variant_builder_init (&details, G_VARIANT_TYPE_VARDICT); + g_dbus_proxy_call (priv->proxy, + "ConnectInteractive", + g_variant_new ("(@a{sa{sv}}a{sv})", priv->connect_hash, &details), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + (GAsyncReadyCallback) connect_interactive_cb, + self); } else { - nm_log_dbg (LOGD_VPN, "Calling old Connect function as not all agents support interactive secrets"); - dbus_g_proxy_begin_call (priv->proxy, "Connect", - connect_cb, connection, NULL, - DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, priv->connect_hash, - G_TYPE_INVALID); + _LOGD ("Calling old Connect function as not all agents support interactive secrets"); + g_dbus_proxy_call (priv->proxy, + "Connect", + g_variant_new ("(@a{sa{sv}})", priv->connect_hash), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + (GAsyncReadyCallback) connect_cb, + self); } - g_hash_table_destroy (details); - _set_vpn_state (connection, STATE_CONNECT, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_CONNECT, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); } -void -nm_vpn_connection_activate (NMVpnConnection *connection) +static void +failure_cb (GDBusProxy *proxy, + guint32 reason, + gpointer user_data) +{ + NMVpnConnection *self = NM_VPN_CONNECTION (user_data); + + plugin_failed (self, reason); +} + +static void +state_changed_cb (GDBusProxy *proxy, + guint32 new_service_state, + gpointer user_data) +{ + NMVpnConnection *self = NM_VPN_CONNECTION (user_data); + + plugin_state_changed (self, new_service_state); +} + +static void +secrets_required_cb (GDBusProxy *proxy, + const char *message, + const char **secrets, + gpointer user_data) +{ + NMVpnConnection *self = NM_VPN_CONNECTION (user_data); + + plugin_interactive_secrets_required (self, message, secrets); +} + +static void +config_cb (GDBusProxy *proxy, + GVariant *dict, + gpointer user_data) +{ + NMVpnConnection *self = NM_VPN_CONNECTION (user_data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + + /* Only list to this signals during and after connection */ + if (priv->vpn_state >= STATE_NEED_AUTH) + nm_vpn_connection_config_get (self, dict); +} + +static void +ip4_config_cb (GDBusProxy *proxy, + GVariant *dict, + gpointer user_data) +{ + NMVpnConnection *self = NM_VPN_CONNECTION (user_data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + + /* Only list to this signals during and after connection */ + if (priv->vpn_state >= STATE_NEED_AUTH) + nm_vpn_connection_ip4_config_get (self, dict); +} + +static void +ip6_config_cb (GDBusProxy *proxy, + GVariant *dict, + gpointer user_data) +{ + NMVpnConnection *self = NM_VPN_CONNECTION (user_data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + + /* Only list to this signals during and after connection */ + if (priv->vpn_state >= STATE_NEED_AUTH) + nm_vpn_connection_ip6_config_get (self, dict); +} + +static void +_name_owner_changed (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + NMVpnConnection *self = NM_VPN_CONNECTION (user_data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + char *owner; + + owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object)); + + if (owner && !priv->service_running) { + /* service appeared */ + priv->service_running = TRUE; + _LOGI ("Saw the service appear; activating connection"); + + /* No need to wait for the timeout any longer */ + nm_clear_g_source (&priv->start_timeout); + + /* Expect success because the VPN service has already appeared */ + _nm_dbus_signal_connect (priv->proxy, "Failure", G_VARIANT_TYPE ("(u)"), + G_CALLBACK (failure_cb), self); + _nm_dbus_signal_connect (priv->proxy, "StateChanged", G_VARIANT_TYPE ("(u)"), + G_CALLBACK (state_changed_cb), self); + _nm_dbus_signal_connect (priv->proxy, "SecretsRequired", G_VARIANT_TYPE ("(sas)"), + G_CALLBACK (secrets_required_cb), self); + _nm_dbus_signal_connect (priv->proxy, "Config", G_VARIANT_TYPE ("(a{sv})"), + G_CALLBACK (config_cb), self); + _nm_dbus_signal_connect (priv->proxy, "Ip4Config", G_VARIANT_TYPE ("(a{sv})"), + G_CALLBACK (ip4_config_cb), self); + _nm_dbus_signal_connect (priv->proxy, "Ip6Config", G_VARIANT_TYPE ("(a{sv})"), + G_CALLBACK (ip6_config_cb), self); + + _set_vpn_state (self, STATE_NEED_AUTH, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + + /* Kick off the secrets requests; first we get existing system secrets + * and ask the plugin if these are sufficient, next we get all existing + * secrets from system and from user agents and ask the plugin again, + * and last we ask the user for new secrets if required. + */ + get_secrets (self, SECRETS_REQ_SYSTEM, NULL); + } else if (!owner && priv->service_running) { + /* service went away */ + priv->service_running = FALSE; + _LOGI ("VPN service disappeared"); + nm_vpn_connection_disconnect (self, NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED, FALSE); + } + + g_free (owner); +} + + +static gboolean +_daemon_exec_timeout (gpointer data) +{ + NMVpnConnection *self = NM_VPN_CONNECTION (data); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + + _LOGW ("Timed out waiting for the service to start"); + priv->start_timeout = 0; + nm_vpn_connection_disconnect (self, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT, FALSE); + + g_object_unref (self); + + return G_SOURCE_REMOVE; +} + +static gboolean +nm_vpn_service_daemon_exec (NMVpnConnection *self, GError **error) { NMVpnConnectionPrivate *priv; - NMSettingVpn *s_vpn; - DBusGConnection *bus; + GPid pid; + char *vpn_argv[4]; + gboolean success = FALSE; + GError *spawn_error = NULL; + int i = 0; - g_return_if_fail (NM_IS_VPN_CONNECTION (connection)); + g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), FALSE); + priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + vpn_argv[i++] = (char *) nm_vpn_plugin_info_get_program (priv->plugin_info); + if (nm_vpn_plugin_info_supports_multiple (priv->plugin_info)) { + vpn_argv[i++] = "--bus-name"; + vpn_argv[i++] = priv->bus_name; + } + vpn_argv[i] = NULL; + g_assert (vpn_argv[0]); - s_vpn = nm_connection_get_setting_vpn (priv->connection); - g_assert (s_vpn); - priv->connection_can_persist = nm_setting_vpn_get_persistent (s_vpn); + success = g_spawn_async (NULL, vpn_argv, NULL, 0, nm_utils_setpgid, NULL, &pid, &spawn_error); - _set_vpn_state (connection, STATE_PREPARE, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); - - bus = nm_dbus_manager_get_connection (nm_dbus_manager_get ()); - priv->proxy = dbus_g_proxy_new_for_name (bus, - nm_vpn_connection_get_service (connection), - NM_VPN_DBUS_PLUGIN_PATH, - NM_VPN_DBUS_PLUGIN_INTERFACE); - - dbus_g_proxy_add_signal (priv->proxy, "Failure", G_TYPE_UINT, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "Failure", - G_CALLBACK (plugin_failed), - connection, NULL); - - /* StateChanged signal */ - dbus_g_proxy_add_signal (priv->proxy, "StateChanged", G_TYPE_UINT, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "StateChanged", - G_CALLBACK (plugin_state_changed), - connection, NULL); - - dbus_g_object_register_marshaller (g_cclosure_marshal_generic, - G_TYPE_NONE, G_TYPE_STRING, G_TYPE_STRV, G_TYPE_INVALID); - dbus_g_proxy_add_signal (priv->proxy, "SecretsRequired", G_TYPE_STRING, G_TYPE_STRV, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (priv->proxy, "SecretsRequired", - G_CALLBACK (plugin_interactive_secrets_required), - connection, NULL); - - _set_vpn_state (connection, STATE_NEED_AUTH, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); - - /* Kick off the secrets requests; first we get existing system secrets - * and ask the plugin if these are sufficient, next we get all existing - * secrets from system and from user agents and ask the plugin again, - * and last we ask the user for new secrets if required. - */ - get_secrets (connection, SECRETS_REQ_SYSTEM, NULL); + if (success) { + _LOGI ("Started the VPN service, PID %ld", (long int) pid); + priv->start_timeout = g_timeout_add_seconds (5, _daemon_exec_timeout, g_object_ref (self)); + } else { + g_set_error (error, + NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, + "%s", spawn_error ? spawn_error->message : "unknown g_spawn_async() error"); + + if (spawn_error) + g_error_free (spawn_error); + } + + return success; } -NMConnection * -nm_vpn_connection_get_connection (NMVpnConnection *connection) +static void +on_proxy_acquired (GObject *object, GAsyncResult *result, gpointer user_data) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL); + NMVpnConnection *self; + NMVpnConnectionPrivate *priv; + gs_free_error GError *error = NULL; + GDBusProxy *proxy; - return NM_VPN_CONNECTION_GET_PRIVATE (connection)->connection; + proxy = g_dbus_proxy_new_for_bus_finish (result, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_VPN_CONNECTION (user_data); + priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + + if (error) { + _LOGE ("failed to acquire dbus proxy for VPN service: %s", + error->message); + _set_vpn_state (self, + STATE_FAILED, + NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, + FALSE); + return; + } + + priv->proxy = proxy; + + g_signal_connect (priv->proxy, "notify::g-name-owner", + G_CALLBACK (_name_owner_changed), self); + _name_owner_changed (G_OBJECT (priv->proxy), NULL, self); + + if (priv->service_running) + return; + + if (!nm_vpn_service_daemon_exec (self, &error)) { + _LOGW ("Could not launch the VPN service. error: %s.", + error->message); + + nm_vpn_connection_disconnect (self, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, FALSE); + } } -const char* -nm_vpn_connection_get_connection_id (NMVpnConnection *connection) +void +nm_vpn_connection_activate (NMVpnConnection *self, + NMVpnPluginInfo *plugin_info) { - NMConnection *c; + NMVpnConnectionPrivate *priv; + NMSettingVpn *s_vpn; + const char *service; - g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL); + g_return_if_fail (NM_IS_VPN_CONNECTION (self)); + g_return_if_fail (NM_IS_VPN_PLUGIN_INFO (plugin_info)); - c = NM_VPN_CONNECTION_GET_PRIVATE (connection)->connection; - return c ? nm_connection_get_id (c) : NULL; + priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + g_return_if_fail (!priv->plugin_info); + + s_vpn = nm_connection_get_setting_vpn (_get_applied_connection (self)); + g_return_if_fail (s_vpn); + + service = nm_setting_vpn_get_service_type (s_vpn); + + if (nm_vpn_plugin_info_supports_multiple (plugin_info)) { + const char *path; + + path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (self)); + if (path) + path = strrchr (path, '/'); + g_return_if_fail (path); + + priv->bus_name = g_strdup_printf ("%s.Connection_%s", service, &path[1]); + } else + priv->bus_name = g_strdup (service); + + priv->connection_can_persist = nm_setting_vpn_get_persistent (s_vpn); + priv->plugin_info = g_object_ref (plugin_info); + priv->cancellable = g_cancellable_new (); + + g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, + NULL, + priv->bus_name, + NM_VPN_DBUS_PLUGIN_PATH, + NM_VPN_DBUS_PLUGIN_INTERFACE, + priv->cancellable, + (GAsyncReadyCallback) on_proxy_acquired, + self); + + _set_vpn_state (self, STATE_PREPARE, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); } NMVpnConnectionState -nm_vpn_connection_get_vpn_state (NMVpnConnection *connection) +nm_vpn_connection_get_vpn_state (NMVpnConnection *self) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NM_VPN_CONNECTION_STATE_UNKNOWN); + g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), NM_VPN_CONNECTION_STATE_UNKNOWN); - return _state_to_nm_vpn_state (NM_VPN_CONNECTION_GET_PRIVATE (connection)->vpn_state); + return _state_to_nm_vpn_state (NM_VPN_CONNECTION_GET_PRIVATE (self)->vpn_state); } const char * -nm_vpn_connection_get_banner (NMVpnConnection *connection) +nm_vpn_connection_get_banner (NMVpnConnection *self) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL); + g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), NULL); - return NM_VPN_CONNECTION_GET_PRIVATE (connection)->banner; + return NM_VPN_CONNECTION_GET_PRIVATE (self)->banner; } NMIP4Config * -nm_vpn_connection_get_ip4_config (NMVpnConnection *connection) +nm_vpn_connection_get_ip4_config (NMVpnConnection *self) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL); + g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), NULL); - return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip4_config; + return NM_VPN_CONNECTION_GET_PRIVATE (self)->ip4_config; } NMIP6Config * -nm_vpn_connection_get_ip6_config (NMVpnConnection *connection) +nm_vpn_connection_get_ip6_config (NMVpnConnection *self) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL); + g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), NULL); - return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip6_config; + return NM_VPN_CONNECTION_GET_PRIVATE (self)->ip6_config; } const char * -nm_vpn_connection_get_ip_iface (NMVpnConnection *connection) +nm_vpn_connection_get_ip_iface (NMVpnConnection *self) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL); + g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), NULL); - return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip_iface; + return NM_VPN_CONNECTION_GET_PRIVATE (self)->ip_iface; } int -nm_vpn_connection_get_ip_ifindex (NMVpnConnection *connection) +nm_vpn_connection_get_ip_ifindex (NMVpnConnection *self) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), -1); + g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), -1); - return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip_ifindex; + return NM_VPN_CONNECTION_GET_PRIVATE (self)->ip_ifindex; } guint32 -nm_vpn_connection_get_ip4_internal_gateway (NMVpnConnection *connection) +nm_vpn_connection_get_ip4_internal_gateway (NMVpnConnection *self) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), 0); + g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), 0); - return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip4_internal_gw; + return NM_VPN_CONNECTION_GET_PRIVATE (self)->ip4_internal_gw; } struct in6_addr * -nm_vpn_connection_get_ip6_internal_gateway (NMVpnConnection *connection) +nm_vpn_connection_get_ip6_internal_gateway (NMVpnConnection *self) { - g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), 0); + g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), 0); - return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip6_internal_gw; + return NM_VPN_CONNECTION_GET_PRIVATE (self)->ip6_internal_gw; } void -nm_vpn_connection_disconnect (NMVpnConnection *connection, +nm_vpn_connection_disconnect (NMVpnConnection *self, NMVpnConnectionStateReason reason, gboolean quitting) { - g_return_if_fail (NM_IS_VPN_CONNECTION (connection)); + g_return_if_fail (NM_IS_VPN_CONNECTION (self)); - _set_vpn_state (connection, STATE_DISCONNECTED, reason, quitting); + _set_vpn_state (self, STATE_DISCONNECTED, reason, quitting); } gboolean -nm_vpn_connection_deactivate (NMVpnConnection *connection, +nm_vpn_connection_deactivate (NMVpnConnection *self, NMVpnConnectionStateReason reason, gboolean quitting) { NMVpnConnectionPrivate *priv; gboolean success = FALSE; - g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), FALSE); + g_return_val_if_fail (NM_IS_VPN_CONNECTION (self), FALSE); - priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + priv = NM_VPN_CONNECTION_GET_PRIVATE (self); if (priv->vpn_state > STATE_UNKNOWN && priv->vpn_state <= STATE_DEACTIVATING) { - _set_vpn_state (connection, STATE_DEACTIVATING, reason, quitting); + _set_vpn_state (self, STATE_DEACTIVATING, reason, quitting); success = TRUE; } return success; @@ -1887,127 +2170,136 @@ nm_vpn_connection_deactivate (NMVpnConnection *connection, /******************************************************************************/ static void -plugin_need_secrets_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data) +plugin_need_secrets_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { - NMVpnConnection *self = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - GError *error = NULL; - char *setting_name; + NMVpnConnection *self; + NMVpnConnectionPrivate *priv; + gs_unref_variant GVariant *reply = NULL; + gs_free_error GError *error = NULL; + const char *setting_name; + + reply = _nm_dbus_proxy_call_finish (proxy, result, G_VARIANT_TYPE ("(s)"), &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_VPN_CONNECTION (user_data); + priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - dbus_g_proxy_end_call (proxy, call, &error, - G_TYPE_STRING, &setting_name, - G_TYPE_INVALID); if (error) { - nm_log_err (LOGD_VPN, "(%s/%s) plugin NeedSecrets request #%d failed: %s %s", - nm_connection_get_uuid (priv->connection), - nm_connection_get_id (priv->connection), - priv->secrets_idx + 1, - g_quark_to_string (error->domain), - error->message); + g_dbus_error_strip_remote_error (error); + _LOGE ("plugin NeedSecrets request #%d failed: %s", + priv->secrets_idx + 1, + error->message); _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); - g_error_free (error); return; } - if (setting_name && strlen (setting_name)) { - /* More secrets required */ + g_variant_get (reply, "(&s)", &setting_name); + if (!strlen (setting_name)) { + _LOGD ("service indicated no additional secrets required"); - if (priv->secrets_idx == SECRETS_REQ_NEW) { - nm_log_err (LOGD_VPN, "(%s/%s) final secrets request failed to provide sufficient secrets", - nm_connection_get_uuid (priv->connection), - nm_connection_get_id (priv->connection)); - _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); - } else { - nm_log_dbg (LOGD_VPN, "(%s/%s) service indicated additional secrets required", - nm_connection_get_uuid (priv->connection), - nm_connection_get_id (priv->connection)); - - get_secrets (self, priv->secrets_idx + 1, NULL); - } + /* No secrets required; we can start the VPN */ + really_activate (self, priv->username); return; } - nm_log_dbg (LOGD_VPN, "(%s/%s) service indicated no additional secrets required", - nm_connection_get_uuid (priv->connection), - nm_connection_get_id (priv->connection)); - - /* No secrets required; we can start the VPN */ - really_activate (self, priv->username); + /* More secrets required */ + if (priv->secrets_idx == SECRETS_REQ_NEW) { + _LOGE ("final secrets request failed to provide sufficient secrets"); + _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); + } else { + _LOGD ("service indicated additional secrets required"); + get_secrets (self, priv->secrets_idx + 1, NULL); + } } static void -plugin_new_secrets_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data) +plugin_new_secrets_cb (GDBusProxy *proxy, GAsyncResult *result, gpointer user_data) { - NMVpnConnection *self = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - GError *error = NULL; + NMVpnConnection *self; + NMVpnConnectionPrivate *priv; + gs_unref_variant GVariant *reply = NULL; + gs_free_error GError *error = NULL; - if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) { - _set_vpn_state (self, STATE_CONNECT, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); - } else { - nm_log_err (LOGD_VPN, "(%s/%s) sending new secrets to the plugin failed: %s %s", - nm_connection_get_uuid (priv->connection), - nm_connection_get_id (priv->connection), - g_quark_to_string (error->domain), - error->message); + reply = g_dbus_proxy_call_finish (proxy, result, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + self = NM_VPN_CONNECTION (user_data); + priv = NM_VPN_CONNECTION_GET_PRIVATE (self); + + if (error) { + g_dbus_error_strip_remote_error (error); + _LOGE ("sending new secrets to the plugin failed: %s", + error->message); _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); - g_error_free (error); - } + } else + _set_vpn_state (self, STATE_CONNECT, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); } static void get_secrets_cb (NMSettingsConnection *connection, - guint32 call_id, + NMSettingsConnectionCallId call_id, const char *agent_username, const char *setting_name, GError *error, gpointer user_data) { NMVpnConnection *self = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - GHashTable *hash; + NMVpnConnectionPrivate *priv; + GVariant *dict; + + g_return_if_fail (NM_IS_VPN_CONNECTION (self)); + + priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - g_return_if_fail (NM_CONNECTION (connection) == priv->connection); + g_return_if_fail (connection && connection == _get_settings_connection (self, FALSE)); g_return_if_fail (call_id == priv->secrets_id); - priv->secrets_id = 0; + priv->secrets_id = NULL; + + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; if (error && priv->secrets_idx >= SECRETS_REQ_NEW) { - nm_log_err (LOGD_VPN, "Failed to request VPN secrets #%d: (%d) %s", - priv->secrets_idx + 1, error->code, error->message); + _LOGE ("Failed to request VPN secrets #%d: (%d) %s", + priv->secrets_idx + 1, error->code, error->message); _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); - } else { - /* Cache the username for later */ - if (agent_username) { - g_free (priv->username); - priv->username = g_strdup (agent_username); - } + return; + } - hash = _hash_with_username (priv->connection, priv->username); + /* Cache the username for later */ + if (agent_username) { + g_free (priv->username); + priv->username = g_strdup (agent_username); + } - if (priv->secrets_idx == SECRETS_REQ_INTERACTIVE) { - nm_log_dbg (LOGD_VPN, "(%s/%s) sending secrets to the plugin", - nm_connection_get_uuid (priv->connection), - nm_connection_get_id (priv->connection)); + dict = _hash_with_username (_get_applied_connection (self), priv->username); - /* Send the secrets back to the plugin */ - dbus_g_proxy_begin_call (priv->proxy, "NewSecrets", - plugin_new_secrets_cb, self, NULL, - DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash, - G_TYPE_INVALID); - } else { - nm_log_dbg (LOGD_VPN, "(%s/%s) asking service if additional secrets are required", - nm_connection_get_uuid (priv->connection), - nm_connection_get_id (priv->connection)); - - /* Ask the VPN service if more secrets are required */ - dbus_g_proxy_begin_call (priv->proxy, "NeedSecrets", - plugin_need_secrets_cb, self, NULL, - DBUS_TYPE_G_MAP_OF_MAP_OF_VARIANT, hash, - G_TYPE_INVALID); - } + if (priv->secrets_idx == SECRETS_REQ_INTERACTIVE) { + _LOGD ("sending secrets to the plugin"); - g_hash_table_destroy (hash); + /* Send the secrets back to the plugin */ + g_dbus_proxy_call (priv->proxy, + "NewSecrets", + g_variant_new ("(@a{sa{sv}})", dict), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + (GAsyncReadyCallback) plugin_new_secrets_cb, + self); + } else { + _LOGD ("asking service if additional secrets are required"); + + /* Ask the VPN service if more secrets are required */ + g_dbus_proxy_call (priv->proxy, + "NeedSecrets", + g_variant_new ("(@a{sa{sv}})", dict), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + (GAsyncReadyCallback) plugin_need_secrets_cb, + self); } } @@ -2018,15 +2310,14 @@ get_secrets (NMVpnConnection *self, { NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); NMSecretAgentGetSecretsFlags flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE; - GError *error = NULL; g_return_if_fail (secrets_idx < SECRETS_REQ_LAST); priv->secrets_idx = secrets_idx; - nm_log_dbg (LOGD_VPN, "(%s/%s) requesting VPN secrets pass #%d", - nm_connection_get_uuid (priv->connection), - nm_connection_get_id (priv->connection), - priv->secrets_idx + 1); + cancel_get_secrets (self); + + _LOGD ("requesting VPN secrets pass #%d", + priv->secrets_idx + 1); switch (priv->secrets_idx) { case SECRETS_REQ_SYSTEM: @@ -2046,44 +2337,35 @@ get_secrets (NMVpnConnection *self, if (nm_active_connection_get_user_requested (NM_ACTIVE_CONNECTION (self))) flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_USER_REQUESTED; - priv->secrets_id = nm_settings_connection_get_secrets (NM_SETTINGS_CONNECTION (priv->connection), + priv->secrets_id = nm_settings_connection_get_secrets (_get_settings_connection (self, FALSE), + _get_applied_connection (self), nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (self)), NM_SETTING_VPN_SETTING_NAME, flags, hints, get_secrets_cb, - self, - &error); - if (!priv->secrets_id) { - if (error) { - nm_log_err (LOGD_VPN, "failed to request VPN secrets #%d: (%d) %s", - priv->secrets_idx + 1, error->code, error->message); - } - _set_vpn_state (self, STATE_FAILED, NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, FALSE); - g_clear_error (&error); - } + self); + g_return_if_fail (priv->secrets_id); } static void -plugin_interactive_secrets_required (DBusGProxy *proxy, +plugin_interactive_secrets_required (NMVpnConnection *self, const char *message, - const char **secrets, - gpointer user_data) + const char **secrets) { - NMVpnConnection *connection = NM_VPN_CONNECTION (user_data); - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); guint32 secrets_len = secrets ? g_strv_length ((char **) secrets) : 0; char **hints; guint32 i; - nm_log_info (LOGD_VPN, "VPN plugin requested secrets; state %s (%d)", - vpn_state_to_string (priv->vpn_state), priv->vpn_state); + _LOGI ("VPN plugin: requested secrets; state %s (%d)", + vpn_state_to_string (priv->vpn_state), priv->vpn_state); g_return_if_fail (priv->vpn_state == STATE_CONNECT || priv->vpn_state == STATE_NEED_AUTH); priv->secrets_idx = SECRETS_REQ_INTERACTIVE; - _set_vpn_state (connection, STATE_NEED_AUTH, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); + _set_vpn_state (self, STATE_NEED_AUTH, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE); /* Copy hints and add message to the end */ hints = g_malloc0 (sizeof (char *) * (secrets_len + 2)); @@ -2092,7 +2374,7 @@ plugin_interactive_secrets_required (DBusGProxy *proxy, if (message) hints[i] = g_strdup_printf ("x-vpn-message:%s", message); - get_secrets (connection, SECRETS_REQ_INTERACTIVE, (const char **) hints); + get_secrets (self, SECRETS_REQ_INTERACTIVE, (const char **) hints); g_strfreev (hints); } @@ -2120,10 +2402,8 @@ device_changed (NMActiveConnection *active, * out that connectivity is down and start its reconnect attempt if it * needs to. */ - if (old_device) { - nm_device_set_vpn4_config (old_device, NULL); - nm_device_set_vpn6_config (old_device, NULL); - } + if (old_device) + remove_parent_device_config (NM_VPN_CONNECTION (active), old_device); if (new_device) apply_parent_device_config (NM_VPN_CONNECTION (active)); @@ -2138,50 +2418,39 @@ nm_vpn_connection_init (NMVpnConnection *self) priv->vpn_state = STATE_WAITING; priv->secrets_idx = SECRETS_REQ_SYSTEM; -} - -static void -constructed (GObject *object) -{ - NMConnection *connection; - - G_OBJECT_CLASS (nm_vpn_connection_parent_class)->constructed (object); - - connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (object)); - NM_VPN_CONNECTION_GET_PRIVATE (object)->connection = g_object_ref (connection); + priv->default_route_manager = g_object_ref (nm_default_route_manager_get ()); + priv->route_manager = g_object_ref (nm_route_manager_get ()); } static void dispose (GObject *object) { - NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object); + NMVpnConnection *self = NM_VPN_CONNECTION (object); + NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self); - if (priv->connect_hash) { - g_hash_table_destroy (priv->connect_hash); - priv->connect_hash = NULL; - } + g_clear_pointer (&priv->connect_hash, g_variant_unref); - if (priv->connect_timeout) { - g_source_remove (priv->connect_timeout); - priv->connect_timeout = 0; - } + nm_clear_g_source (&priv->connect_timeout); - dispatcher_cleanup (NM_VPN_CONNECTION (object)); + dispatcher_cleanup (self); - if (priv->secrets_id) { - nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), - priv->secrets_id); - priv->secrets_id = 0; - } + cancel_get_secrets (self); - g_clear_object (&priv->ip4_config); - g_clear_object (&priv->ip6_config); + if (priv->cancellable) { + g_cancellable_cancel (priv->cancellable); + g_clear_object (&priv->cancellable); + } + nm_exported_object_clear_and_unexport (&priv->ip4_config); + nm_exported_object_clear_and_unexport (&priv->ip6_config); g_clear_object (&priv->proxy); - g_clear_object (&priv->connection); + g_clear_object (&priv->plugin_info); - fw_call_cleanup (NM_VPN_CONNECTION (object)); + fw_call_cleanup (self); G_OBJECT_CLASS (nm_vpn_connection_parent_class)->dispose (object); + + g_clear_object (&priv->default_route_manager); + g_clear_object (&priv->route_manager); } static void @@ -2206,7 +2475,7 @@ ip_config_valid (VpnState state) static void get_property (GObject *object, guint prop_id, - GValue *value, GParamSpec *pspec) + GValue *value, GParamSpec *pspec) { NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object); NMDevice *parent_dev; @@ -2219,20 +2488,14 @@ get_property (GObject *object, guint prop_id, g_value_set_string (value, priv->banner ? priv->banner : ""); break; case PROP_IP4_CONFIG: - if (ip_config_valid (priv->vpn_state) && priv->ip4_config) - g_value_set_boxed (value, nm_ip4_config_get_dbus_path (priv->ip4_config)); - else - g_value_set_boxed (value, "/"); + nm_utils_g_value_set_object_path (value, ip_config_valid (priv->vpn_state) ? priv->ip4_config : NULL); break; case PROP_IP6_CONFIG: - if (ip_config_valid (priv->vpn_state) && priv->ip6_config) - g_value_set_boxed (value, nm_ip6_config_get_dbus_path (priv->ip6_config)); - else - g_value_set_boxed (value, "/"); + nm_utils_g_value_set_object_path (value, ip_config_valid (priv->vpn_state) ? priv->ip6_config : NULL); break; case PROP_MASTER: parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object)); - g_value_set_boxed (value, parent_dev ? nm_device_get_path (parent_dev) : "/"); + nm_utils_g_value_set_object_path (value, parent_dev); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -2250,7 +2513,6 @@ nm_vpn_connection_class_init (NMVpnConnectionClass *connection_class) /* virtual methods */ object_class->get_property = get_property; - object_class->constructed = constructed; object_class->dispose = dispose; object_class->finalize = finalize; active_class->device_state_changed = device_state_changed; @@ -2302,8 +2564,7 @@ nm_vpn_connection_class_init (NMVpnConnectionClass *connection_class) 0, NULL, NULL, NULL, G_TYPE_NONE, 0); - nm_dbus_manager_register_exported_type (nm_dbus_manager_get (), - G_TYPE_FROM_CLASS (object_class), - &dbus_glib_nm_vpn_connection_object_info); + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (connection_class), + NMDBUS_TYPE_VPN_CONNECTION_SKELETON, + NULL); } - diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h index 0e63caac..19b0eb3f 100644 --- a/src/vpn-manager/nm-vpn-connection.h +++ b/src/vpn-manager/nm-vpn-connection.h @@ -22,12 +22,11 @@ #ifndef __NETWORKMANAGER_VPN_CONNECTION_H__ #define __NETWORKMANAGER_VPN_CONNECTION_H__ -#include -#include #include "nm-vpn-dbus-interface.h" #include "nm-device.h" #include "nm-auth-subject.h" #include "nm-active-connection.h" +#include "nm-vpn-plugin-info.h" #define NM_TYPE_VPN_CONNECTION (nm_vpn_connection_get_type ()) #define NM_VPN_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_CONNECTION, NMVpnConnection)) @@ -57,47 +56,47 @@ typedef struct { NMActiveConnectionClass parent; /* Signals */ - void (*vpn_state_changed) (NMVpnConnection *connection, + void (*vpn_state_changed) (NMVpnConnection *self, NMVpnConnectionState new_state, NMVpnConnectionStateReason reason); /* not exported over D-Bus */ - void (*internal_state_changed) (NMVpnConnection *connection, + void (*internal_state_changed) (NMVpnConnection *self, NMVpnConnectionState new_state, NMVpnConnectionState old_state, NMVpnConnectionStateReason reason); - void (*internal_failed_retry) (NMVpnConnection *connection); + void (*internal_failed_retry) (NMVpnConnection *self); } NMVpnConnectionClass; GType nm_vpn_connection_get_type (void); -NMVpnConnection * nm_vpn_connection_new (NMConnection *connection, +NMVpnConnection * nm_vpn_connection_new (NMSettingsConnection *settings_connection, NMDevice *parent_device, const char *specific_object, NMAuthSubject *subject); -void nm_vpn_connection_activate (NMVpnConnection *connection); -NMConnection * nm_vpn_connection_get_connection (NMVpnConnection *connection); -const char* nm_vpn_connection_get_connection_id (NMVpnConnection *connection); -NMVpnConnectionState nm_vpn_connection_get_vpn_state (NMVpnConnection *connection); -const char * nm_vpn_connection_get_banner (NMVpnConnection *connection); +void nm_vpn_connection_activate (NMVpnConnection *self, + NMVpnPluginInfo *plugin_info); +NMVpnConnectionState nm_vpn_connection_get_vpn_state (NMVpnConnection *self); +const char * nm_vpn_connection_get_banner (NMVpnConnection *self); +const gchar * nm_vpn_connection_get_service (NMVpnConnection *self); -gboolean nm_vpn_connection_deactivate (NMVpnConnection *connection, +gboolean nm_vpn_connection_deactivate (NMVpnConnection *self, NMVpnConnectionStateReason reason, gboolean quitting); -void nm_vpn_connection_disconnect (NMVpnConnection *connection, +void nm_vpn_connection_disconnect (NMVpnConnection *self, NMVpnConnectionStateReason reason, gboolean quitting); -NMIP4Config * nm_vpn_connection_get_ip4_config (NMVpnConnection *connection); -NMIP6Config * nm_vpn_connection_get_ip6_config (NMVpnConnection *connection); -const char * nm_vpn_connection_get_ip_iface (NMVpnConnection *connection); -int nm_vpn_connection_get_ip_ifindex (NMVpnConnection *connection); -guint32 nm_vpn_connection_get_ip4_internal_gateway (NMVpnConnection *connection); -struct in6_addr * nm_vpn_connection_get_ip6_internal_gateway (NMVpnConnection *connection); +NMIP4Config * nm_vpn_connection_get_ip4_config (NMVpnConnection *self); +NMIP6Config * nm_vpn_connection_get_ip6_config (NMVpnConnection *self); +const char * nm_vpn_connection_get_ip_iface (NMVpnConnection *self); +int nm_vpn_connection_get_ip_ifindex (NMVpnConnection *self); +guint32 nm_vpn_connection_get_ip4_internal_gateway (NMVpnConnection *self); +struct in6_addr * nm_vpn_connection_get_ip6_internal_gateway (NMVpnConnection *self); -guint32 nm_vpn_connection_get_ip4_route_metric (NMVpnConnection *connection); -guint32 nm_vpn_connection_get_ip6_route_metric (NMVpnConnection *connection); +guint32 nm_vpn_connection_get_ip4_route_metric (NMVpnConnection *self); +guint32 nm_vpn_connection_get_ip6_route_metric (NMVpnConnection *self); #endif /* __NETWORKMANAGER_VPN_CONNECTION_H__ */ diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c index 1de9b753..45d22998 100644 --- a/src/vpn-manager/nm-vpn-manager.c +++ b/src/vpn-manager/nm-vpn-manager.c @@ -22,50 +22,48 @@ #include "config.h" #include -#include +#include "nm-default.h" #include "nm-vpn-manager.h" -#include "nm-vpn-service.h" +#include "nm-vpn-plugin-info.h" #include "nm-vpn-connection.h" #include "nm-setting-vpn.h" -#include "nm-dbus-manager.h" #include "nm-vpn-dbus-interface.h" +#include "nm-core-internal.h" #include "nm-enum-types.h" -#include "nm-logging.h" - -#define VPN_NAME_FILES_DIR NMCONFDIR "/VPN" G_DEFINE_TYPE (NMVpnManager, nm_vpn_manager, G_TYPE_OBJECT) #define NM_VPN_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_MANAGER, NMVpnManagerPrivate)) typedef struct { - GHashTable *services; - GFileMonitor *monitor; - guint monitor_id; + GSList *plugins; + GFileMonitor *monitor_etc; + GFileMonitor *monitor_lib; + gulong monitor_id_etc; + gulong monitor_id_lib; + + /* This is only used for services that don't support multiple + * connections, to guard access to them. */ + GHashTable *active_services; } NMVpnManagerPrivate; +/******************************************************************************/ -static NMVpnService * -get_service_by_namefile (NMVpnManager *self, const char *namefile) +static void +vpn_state_changed (NMVpnConnection *vpn, + GParamSpec *pspec, + NMVpnManager *manager) { - NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self); - GHashTableIter iter; - gpointer data; - - g_return_val_if_fail (namefile, NULL); - g_return_val_if_fail (g_path_is_absolute (namefile), NULL); - - g_hash_table_iter_init (&iter, priv->services); - while (g_hash_table_iter_next (&iter, NULL, &data)) { - NMVpnService *candidate = NM_VPN_SERVICE (data); - const char *service_namefile; - - service_namefile = nm_vpn_service_get_name_file (candidate); - if (!strcmp (namefile, service_namefile)) - return candidate; + NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (manager); + NMActiveConnectionState state = nm_active_connection_get_state (NM_ACTIVE_CONNECTION (vpn)); + const char *service_name = nm_vpn_connection_get_service (vpn); + + if (state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) { + g_hash_table_remove (priv->active_services, service_name); + g_signal_handlers_disconnect_by_func (vpn, vpn_state_changed, manager); + g_object_unref (manager); } - return NULL; } gboolean @@ -73,17 +71,16 @@ nm_vpn_manager_activate_connection (NMVpnManager *manager, NMVpnConnection *vpn, GError **error) { - NMConnection *connection; - NMSettingVpn *s_vpn; - NMVpnService *service; + NMVpnManagerPrivate *priv; + NMVpnPluginInfo *plugin_info; const char *service_name; NMDevice *device; g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), FALSE); g_return_val_if_fail (NM_IS_VPN_CONNECTION (vpn), FALSE); - g_return_val_if_fail (error != NULL, FALSE); - g_return_val_if_fail (*error == NULL, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + priv = NM_VPN_MANAGER_GET_PRIVATE (manager); device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn)); g_assert (device); if ( nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED @@ -93,63 +90,57 @@ nm_vpn_manager_activate_connection (NMVpnManager *manager, return FALSE; } - connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (vpn)); - g_assert (connection); - s_vpn = nm_connection_get_setting_vpn (connection); - g_assert (s_vpn); + service_name = nm_vpn_connection_get_service (vpn); - service_name = nm_setting_vpn_get_service_type (s_vpn); - g_assert (service_name); - service = g_hash_table_lookup (NM_VPN_MANAGER_GET_PRIVATE (manager)->services, service_name); - if (!service) { + plugin_info = nm_vpn_plugin_info_list_find_by_service (priv->plugins, service_name); + if (!plugin_info) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE, "The VPN service '%s' was not installed.", service_name); return FALSE; } - return nm_vpn_service_activate (service, vpn, error); -} + if ( !nm_vpn_plugin_info_supports_multiple (plugin_info) + && g_hash_table_contains (priv->active_services, service_name)) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE, + "The '%s' plugin only supports a single active connection.", + nm_vpn_plugin_info_get_name (plugin_info)); + return FALSE; + } -gboolean -nm_vpn_manager_deactivate_connection (NMVpnManager *self, - NMVpnConnection *connection, - NMVpnConnectionStateReason reason) -{ - return nm_vpn_connection_deactivate (connection, reason, FALSE); + nm_vpn_connection_activate (vpn, plugin_info); + + if (!nm_vpn_plugin_info_supports_multiple (plugin_info)) { + /* Block activations of the connections of the same service type. */ + g_hash_table_add (priv->active_services, g_strdup (service_name)); + g_signal_connect (vpn, "notify::" NM_ACTIVE_CONNECTION_STATE, + G_CALLBACK (vpn_state_changed), + g_object_ref (manager)); + } + + return TRUE; } +/******************************************************************************/ + static void -try_add_service (NMVpnManager *self, const char *namefile) +try_add_plugin (NMVpnManager *self, NMVpnPluginInfo *plugin_info) { NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self); - NMVpnService *service = NULL; - GHashTableIter iter; - GError *error = NULL; - const char *service_name; - - g_return_if_fail (g_path_is_absolute (namefile)); + const char *program; - /* Make sure we don't add dupes */ - g_hash_table_iter_init (&iter, priv->services); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &service)) { - if (g_strcmp0 (namefile, nm_vpn_service_get_name_file (service)) == 0) - return; - } + program = nm_vpn_plugin_info_get_program (plugin_info); + if (!program || !*program) + return; - /* New service */ - service = nm_vpn_service_new (namefile, &error); - if (service) { - service_name = nm_vpn_service_get_dbus_service (service); - g_hash_table_insert (priv->services, (char *) service_name, service); - nm_log_info (LOGD_VPN, "VPN: loaded %s", service_name); - } else { - nm_log_warn (LOGD_VPN, "failed to load VPN service file %s: (%d) %s", - namefile, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); - g_clear_error (&error); - } + /* Make sure we don't add dupes. + * We don't really allow reload of the same file. What we do allow is however to + * delete a file and re-add it. */ + if (nm_vpn_plugin_info_list_find_by_filename (priv->plugins, + nm_vpn_plugin_info_get_filename (plugin_info))) + return; + if (!nm_vpn_plugin_info_list_add (&priv->plugins, plugin_info, NULL)) + return; } static void @@ -161,41 +152,55 @@ vpn_dir_changed (GFileMonitor *monitor, { NMVpnManager *self = NM_VPN_MANAGER (user_data); NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self); - NMVpnService *service; - char *path; + NMVpnPluginInfo *plugin_info; + gs_free char *path = NULL; + GError *error = NULL; path = g_file_get_path (file); - if (!g_str_has_suffix (path, ".name")) { - g_free (path); + if (!nm_vpn_plugin_info_validate_filename (path)) return; - } switch (event_type) { case G_FILE_MONITOR_EVENT_DELETED: - nm_log_dbg (LOGD_VPN, "service file %s deleted", path); - - service = get_service_by_namefile (self, path); - if (service) { - const char *service_name = nm_vpn_service_get_dbus_service (service); + plugin_info = nm_vpn_plugin_info_list_find_by_filename (priv->plugins, path); + if (!plugin_info) + break; - /* Stop active VPN connections and destroy the service */ - nm_vpn_service_stop_connections (service, FALSE, - NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED); - nm_log_info (LOGD_VPN, "VPN: unloaded %s", service_name); - g_hash_table_remove (priv->services, service_name); - } + nm_log_dbg (LOGD_VPN, "vpn: service file %s deleted", path); + nm_vpn_plugin_info_list_remove (&priv->plugins, plugin_info); break; case G_FILE_MONITOR_EVENT_CREATED: case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: - nm_log_dbg (LOGD_VPN, "service file %s created or modified", path); - try_add_service (self, path); + plugin_info = nm_vpn_plugin_info_list_find_by_filename (priv->plugins, path); + if (plugin_info) { + /* we don't support reloading an existing plugin. You can only remove the file + * and re-add it. By reloading we want to support the use case of installing + * a VPN plugin after NM started. No need to burden ourself with a complete + * reload. */ + break; + } + + if (!_nm_vpn_plugin_info_check_file (path, TRUE, TRUE, 0, + NULL, NULL, &error)) { + nm_log_dbg (LOGD_VPN, "vpn: ignore changed service file %s (%s)", path, error->message); + g_clear_error (&error); + break; + } + plugin_info = nm_vpn_plugin_info_new_from_file (path, &error); + if (!plugin_info) { + nm_log_dbg (LOGD_VPN, "vpn: ignore changed service file %s due to invalid content (%s)", path, error->message); + g_clear_error (&error); + break; + } + + nm_log_dbg (LOGD_VPN, "vpn: service file %s created or modified", path); + try_add_plugin (self, plugin_info); + g_object_unref (plugin_info); break; default: - nm_log_dbg (LOGD_VPN, "service file %s change event %d", path, event_type); + nm_log_dbg (LOGD_VPN, "vpn: service file %s change event %d", path, event_type); break; } - - g_free (path); } /******************************************************************************/ @@ -207,50 +212,42 @@ nm_vpn_manager_init (NMVpnManager *self) { NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self); GFile *file; - GDir *dir; - const char *fn; - char *path; - - priv->services = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, g_object_unref); + GSList *infos, *info; + const char *conf_dir_etc = _nm_vpn_plugin_info_get_default_dir_etc (); + const char *conf_dir_lib = _nm_vpn_plugin_info_get_default_dir_lib (); /* Watch the VPN directory for changes */ - file = g_file_new_for_path (VPN_NAME_FILES_DIR "/"); - priv->monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); + file = g_file_new_for_path (conf_dir_lib); + priv->monitor_lib = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); g_object_unref (file); - if (priv->monitor) { - priv->monitor_id = g_signal_connect (priv->monitor, "changed", - G_CALLBACK (vpn_dir_changed), self); + if (priv->monitor_lib) { + priv->monitor_id_lib = g_signal_connect (priv->monitor_lib, "changed", + G_CALLBACK (vpn_dir_changed), self); } - /* Load VPN service files */ - dir = g_dir_open (VPN_NAME_FILES_DIR, 0, NULL); - if (dir) { - while ((fn = g_dir_read_name (dir))) { - /* only parse filenames that end with .name */ - if (g_str_has_suffix (fn, ".name")) { - path = g_build_filename (VPN_NAME_FILES_DIR, fn, NULL); - try_add_service (self, path); - g_free (path); - } - } - g_dir_close (dir); + file = g_file_new_for_path (conf_dir_etc); + priv->monitor_etc = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref (file); + if (priv->monitor_etc) { + priv->monitor_id_etc = g_signal_connect (priv->monitor_etc, "changed", + G_CALLBACK (vpn_dir_changed), self); } -} -static void -stop_all_services (NMVpnManager *self) -{ - NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self); - GHashTableIter iter; - NMVpnService *service; - - g_hash_table_iter_init (&iter, priv->services); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &service)) { - nm_vpn_service_stop_connections (service, - TRUE, - NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED); - } + /* first read conf_dir_lib. The name files are not really user configuration, but + * plugin configuration. Hence we expect ~newer~ plugins to install their files + * in /usr/lib/NetworkManager. We want to prefer those files. + * In case of no-conflict, the order doesn't matter. */ + infos = _nm_vpn_plugin_info_list_load_dir (conf_dir_lib, TRUE, 0, NULL, NULL); + for (info = infos; info; info = info->next) + try_add_plugin (self, info->data); + g_slist_free_full (infos, g_object_unref); + + infos = _nm_vpn_plugin_info_list_load_dir (conf_dir_etc, TRUE, 0, NULL, NULL); + for (info = infos; info; info = info->next) + try_add_plugin (self, info->data); + g_slist_free_full (infos, g_object_unref); + + priv->active_services = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); } static void @@ -258,19 +255,25 @@ dispose (GObject *object) { NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (object); - if (priv->monitor) { - if (priv->monitor_id) - g_signal_handler_disconnect (priv->monitor, priv->monitor_id); - g_file_monitor_cancel (priv->monitor); - g_clear_object (&priv->monitor); + if (priv->monitor_etc) { + if (priv->monitor_id_etc) + g_signal_handler_disconnect (priv->monitor_etc, priv->monitor_id_etc); + g_file_monitor_cancel (priv->monitor_etc); + g_clear_object (&priv->monitor_etc); } - if (priv->services) { - stop_all_services (NM_VPN_MANAGER (object)); - g_hash_table_destroy (priv->services); - priv->services = NULL; + if (priv->monitor_lib) { + if (priv->monitor_id_lib) + g_signal_handler_disconnect (priv->monitor_lib, priv->monitor_id_lib); + g_file_monitor_cancel (priv->monitor_lib); + g_clear_object (&priv->monitor_lib); } + while (priv->plugins) + nm_vpn_plugin_info_list_remove (&priv->plugins, priv->plugins->data); + + g_hash_table_unref (priv->active_services); + G_OBJECT_CLASS (nm_vpn_manager_parent_class)->dispose (object); } diff --git a/src/vpn-manager/nm-vpn-manager.h b/src/vpn-manager/nm-vpn-manager.h index b75a6179..f557e27a 100644 --- a/src/vpn-manager/nm-vpn-manager.h +++ b/src/vpn-manager/nm-vpn-manager.h @@ -22,8 +22,7 @@ #ifndef __NETWORKMANAGER_VPN_MANAGER_H__ #define __NETWORKMANAGER_VPN_MANAGER_H__ -#include -#include +#include "nm-default.h" #include "nm-vpn-connection.h" #define NM_TYPE_VPN_MANAGER (nm_vpn_manager_get_type ()) @@ -49,8 +48,4 @@ gboolean nm_vpn_manager_activate_connection (NMVpnManager *manager, NMVpnConnection *vpn, GError **error); -gboolean nm_vpn_manager_deactivate_connection (NMVpnManager *manager, - NMVpnConnection *connection, - NMVpnConnectionStateReason reason); - #endif /* __NETWORKMANAGER_VPN_MANAGER_H__ */ diff --git a/src/vpn-manager/nm-vpn-service.c b/src/vpn-manager/nm-vpn-service.c deleted file mode 100644 index 77220dd2..00000000 --- a/src/vpn-manager/nm-vpn-service.c +++ /dev/null @@ -1,385 +0,0 @@ -/* -*- 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 - 2014 Red Hat, Inc. - * Copyright (C) 2005 - 2008 Novell, Inc. - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include "nm-vpn-service.h" -#include "nm-dbus-manager.h" -#include "nm-logging.h" -#include "nm-vpn-manager.h" -#include "nm-glib-compat.h" - -G_DEFINE_TYPE (NMVpnService, nm_vpn_service, G_TYPE_OBJECT) - -typedef struct { - char *name; - char *dbus_service; - char *program; - char *namefile; - - NMVpnConnection *active; - GSList *pending; - - guint start_timeout; - gboolean service_running; -} NMVpnServicePrivate; - -#define NM_VPN_SERVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_SERVICE, NMVpnServicePrivate)) - -#define VPN_CONNECTION_GROUP "VPN Connection" - -static gboolean start_pending_vpn (NMVpnService *self, GError **error); - -NMVpnService * -nm_vpn_service_new (const char *namefile, GError **error) -{ - NMVpnService *self; - NMVpnServicePrivate *priv; - GKeyFile *kf; - - g_return_val_if_fail (namefile != NULL, NULL); - g_return_val_if_fail (g_path_is_absolute (namefile), NULL); - - kf = g_key_file_new (); - if (!g_key_file_load_from_file (kf, namefile, G_KEY_FILE_NONE, error)) { - g_key_file_free (kf); - return NULL; - } - - self = (NMVpnService *) g_object_new (NM_TYPE_VPN_SERVICE, NULL); - priv = NM_VPN_SERVICE_GET_PRIVATE (self); - priv->namefile = g_strdup (namefile); - - priv->dbus_service = g_key_file_get_string (kf, VPN_CONNECTION_GROUP, "service", error); - if (!priv->dbus_service) - goto error; - - priv->program = g_key_file_get_string (kf, VPN_CONNECTION_GROUP, "program", error); - if (!priv->program) - goto error; - - priv->name = g_key_file_get_string (kf, VPN_CONNECTION_GROUP, "name", error); - if (!priv->name) - goto error; - - priv->service_running = nm_dbus_manager_name_has_owner (nm_dbus_manager_get (), priv->dbus_service); - - g_key_file_free (kf); - return self; - -error: - g_object_unref (self); - g_key_file_free (kf); - return NULL; -} - -const char * -nm_vpn_service_get_dbus_service (NMVpnService *service) -{ - g_return_val_if_fail (NM_IS_VPN_SERVICE (service), NULL); - - return NM_VPN_SERVICE_GET_PRIVATE (service)->dbus_service; -} - -const char * -nm_vpn_service_get_name_file (NMVpnService *service) -{ - g_return_val_if_fail (NM_IS_VPN_SERVICE (service), NULL); - - return NM_VPN_SERVICE_GET_PRIVATE (service)->namefile; -} - -static void -connection_vpn_state_changed (NMVpnConnection *connection, - NMVpnConnectionState new_state, - NMVpnConnectionState old_state, - NMVpnConnectionStateReason reason, - gpointer user_data) -{ - NMVpnService *self = NM_VPN_SERVICE (user_data); - NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self); - - if (new_state == NM_VPN_CONNECTION_STATE_FAILED || - new_state == NM_VPN_CONNECTION_STATE_DISCONNECTED) { - g_signal_handlers_disconnect_by_func (connection, G_CALLBACK (connection_vpn_state_changed), self); - if (connection == priv->active) { - priv->active = NULL; - start_pending_vpn (self, NULL); - } else - priv->pending = g_slist_remove (priv->pending, connection); - g_object_unref (connection); - } -} - -void -nm_vpn_service_stop_connections (NMVpnService *service, - gboolean quitting, - NMVpnConnectionStateReason reason) -{ - NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (service); - GSList *iter; - - /* Just add priv->active to the beginning of priv->pending, - * since we're going to clear priv->pending immediately anyway. - */ - if (priv->active) { - priv->pending = g_slist_prepend (priv->pending, priv->active); - priv->active = NULL; - } - - for (iter = priv->pending; iter; iter = iter->next) { - NMVpnConnection *vpn = NM_VPN_CONNECTION (iter->data); - - g_signal_handlers_disconnect_by_func (vpn, G_CALLBACK (connection_vpn_state_changed), service); - if (quitting) { - /* Deactivate to allow pre-down before disconnecting */ - nm_vpn_connection_deactivate (vpn, reason, quitting); - } - nm_vpn_connection_disconnect (vpn, reason, quitting); - g_object_unref (vpn); - } - g_clear_pointer (&priv->pending, g_slist_free); -} - -static gboolean -_daemon_exec_timeout (gpointer data) -{ - NMVpnService *self = NM_VPN_SERVICE (data); - NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self); - - nm_log_warn (LOGD_VPN, "VPN service '%s' start timed out", priv->name); - priv->start_timeout = 0; - nm_vpn_service_stop_connections (self, FALSE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT); - return G_SOURCE_REMOVE; -} - -static gboolean -nm_vpn_service_daemon_exec (NMVpnService *service, GError **error) -{ - NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (service); - GPid pid; - char *vpn_argv[2]; - gboolean success = FALSE; - GError *spawn_error = NULL; - - g_return_val_if_fail (NM_IS_VPN_SERVICE (service), FALSE); - - vpn_argv[0] = priv->program; - vpn_argv[1] = NULL; - - success = g_spawn_async (NULL, vpn_argv, NULL, 0, nm_utils_setpgid, NULL, &pid, &spawn_error); - if (success) { - nm_log_info (LOGD_VPN, "VPN service '%s' started (%s), PID %ld", - priv->name, priv->dbus_service, (long int) pid); - priv->start_timeout = g_timeout_add_seconds (5, _daemon_exec_timeout, service); - } else { - nm_log_warn (LOGD_VPN, "VPN service '%s': could not launch the VPN service. error: (%d) %s.", - priv->name, - spawn_error ? spawn_error->code : -1, - spawn_error && spawn_error->message ? spawn_error->message : "(unknown)"); - - g_set_error (error, - NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "%s", spawn_error ? spawn_error->message : "unknown g_spawn_async() error"); - - nm_vpn_service_stop_connections (service, FALSE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED); - if (spawn_error) - g_error_free (spawn_error); - } - - return success; -} - -static gboolean -start_active_vpn (NMVpnService *self, GError **error) -{ - NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self); - - if (!priv->active) - return TRUE; - - if (priv->service_running) { - /* Just activate the VPN */ - nm_vpn_connection_activate (priv->active); - return TRUE; - } else if (priv->start_timeout == 0) { - /* VPN service not running, start it */ - nm_log_info (LOGD_VPN, "Starting VPN service '%s'...", priv->name); - return nm_vpn_service_daemon_exec (self, error); - } - - /* Already started VPN service, waiting for it to appear on D-Bus */ - return TRUE; -} - -static gboolean -start_pending_vpn (NMVpnService *self, GError **error) -{ - NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self); - - g_assert (priv->active == NULL); - - if (!priv->pending) - return TRUE; - - /* Make next VPN active */ - priv->active = g_slist_nth_data (priv->pending, 0); - priv->pending = g_slist_remove (priv->pending, priv->active); - - return start_active_vpn (self, error); -} - -gboolean -nm_vpn_service_activate (NMVpnService *service, - NMVpnConnection *vpn, - GError **error) -{ - NMVpnServicePrivate *priv; - - g_return_val_if_fail (NM_IS_VPN_SERVICE (service), FALSE); - g_return_val_if_fail (NM_IS_VPN_CONNECTION (vpn), FALSE); - g_return_val_if_fail (error != NULL, FALSE); - g_return_val_if_fail (*error == NULL, FALSE); - - priv = NM_VPN_SERVICE_GET_PRIVATE (service); - - g_signal_connect (vpn, NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED, - G_CALLBACK (connection_vpn_state_changed), - service); - - /* Queue up the new VPN connection */ - priv->pending = g_slist_append (priv->pending, g_object_ref (vpn)); - - /* Tell the active VPN to deactivate and wait for it to quit before we - * start the next VPN. The just-queued VPN will then be started from - * connection_vpn_state_changed(). - */ - if (priv->active) { - nm_vpn_connection_deactivate (priv->active, NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED, FALSE); - return TRUE; - } - - /* Otherwise start the next VPN */ - return start_pending_vpn (service, error); -} - -static void -_name_owner_changed (NMDBusManager *mgr, - const char *name, - const char *old, - const char *new, - gpointer user_data) -{ - NMVpnService *service = NM_VPN_SERVICE (user_data); - NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (service); - gboolean old_owner_good, new_owner_good, success; - - if (strcmp (name, priv->dbus_service)) - return; - - /* Service changed, no need to wait for the timeout any longer */ - if (priv->start_timeout) { - g_source_remove (priv->start_timeout); - priv->start_timeout = 0; - } - - old_owner_good = (old && old[0]); - new_owner_good = (new && new[0]); - - if (!old_owner_good && new_owner_good) { - /* service appeared */ - priv->service_running = TRUE; - nm_log_info (LOGD_VPN, "VPN service '%s' appeared; activating connections", priv->name); - /* Expect success because the VPN service has already appeared */ - success = start_active_vpn (service, NULL); - g_warn_if_fail (success); - } else if (old_owner_good && !new_owner_good) { - /* service went away */ - priv->service_running = FALSE; - nm_log_info (LOGD_VPN, "VPN service '%s' disappeared", priv->name); - nm_vpn_service_stop_connections (service, FALSE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED); - } -} - -/******************************************************************************/ - -static void -nm_vpn_service_init (NMVpnService *self) -{ - g_signal_connect (nm_dbus_manager_get (), - NM_DBUS_MANAGER_NAME_OWNER_CHANGED, - G_CALLBACK (_name_owner_changed), - self); -} - -static void -dispose (GObject *object) -{ - NMVpnService *self = NM_VPN_SERVICE (object); - NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self); - - if (priv->start_timeout) { - g_source_remove (priv->start_timeout); - priv->start_timeout = 0; - } - - /* VPNService owner is required to stop connections before releasing */ - g_assert (priv->active == NULL); - g_assert (priv->pending == NULL); - - g_signal_handlers_disconnect_by_func (nm_dbus_manager_get (), - G_CALLBACK (_name_owner_changed), - self); - - G_OBJECT_CLASS (nm_vpn_service_parent_class)->dispose (object); -} - -static void -finalize (GObject *object) -{ - NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (object); - - g_free (priv->name); - g_free (priv->dbus_service); - g_free (priv->program); - g_free (priv->namefile); - - G_OBJECT_CLASS (nm_vpn_service_parent_class)->finalize (object); -} - -static void -nm_vpn_service_class_init (NMVpnServiceClass *service_class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (service_class); - - g_type_class_add_private (service_class, sizeof (NMVpnServicePrivate)); - - /* virtual methods */ - object_class->dispose = dispose; - object_class->finalize = finalize; -} diff --git a/src/vpn-manager/nm-vpn-service.h b/src/vpn-manager/nm-vpn-service.h deleted file mode 100644 index cafa6904..00000000 --- a/src/vpn-manager/nm-vpn-service.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- 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) 2005 - 2008 Novell, Inc. - */ - -#ifndef __NETWORKMANAGER_VPN_SERVICE_H__ -#define __NETWORKMANAGER_VPN_SERVICE_H__ - -#include -#include -#include "nm-device.h" -#include "nm-vpn-connection.h" - -#define NM_TYPE_VPN_SERVICE (nm_vpn_service_get_type ()) -#define NM_VPN_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_SERVICE, NMVpnService)) -#define NM_VPN_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_VPN_SERVICE, NMVpnServiceClass)) -#define NM_IS_VPN_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_VPN_SERVICE)) -#define NM_IS_VPN_SERVICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_VPN_SERVICE)) -#define NM_VPN_SERVICE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_VPN_SERVICE, NMVpnServiceClass)) - -typedef struct { - GObject parent; -} NMVpnService; - -typedef struct { - GObjectClass parent; -} NMVpnServiceClass; - -GType nm_vpn_service_get_type (void); - -NMVpnService * nm_vpn_service_new (const char *namefile, GError **error); - -/* Returns the VPN service's D-Bus service name */ -const char *nm_vpn_service_get_dbus_service (NMVpnService *service); - -/* Returns the path of the VPN service's .name file */ -const char *nm_vpn_service_get_name_file (NMVpnService *service); - -gboolean nm_vpn_service_activate (NMVpnService *service, - NMVpnConnection *vpn, - GError **error); - -void nm_vpn_service_stop_connections (NMVpnService *service, - gboolean quitting, - NMVpnConnectionStateReason reason); - -#endif /* NM_VPN_VPN_SERVICE_H */ -- cgit 1.3.0-6-gf8a5